功能基本齐全,有需要的自己加 两坨屎山,卤棒性较差。目前没有发现bug。
#include <winsock2.h>
#include <iostream>
#include <bits/stdc++.h>
#include <time.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
vector<string> wait;
map<string,bool> gotR;
map<SOCKET,string> usrname;
map<string,SOCKET> isused;
map<string,string> match;
map<string,int> chs;
map<string,bool> isinque;
string mp;
string hd[4] = {"未出手","石头","剪刀","布"};
void Send(SOCKET s,string str){
char buf[300] = {0};
sprintf(buf, str.c_str());
send(s, buf, 300, 0);
}
int win(int a,int b){
if(a == b)
return -1;
if(a == 1 && b == 2)
return 1;
if(a == 2 && b == 3)
return 1;
if(a == 3 && b == 1)
return 1;
return 0;
}
void save(string str){
fstream f;
f.open("chat.tmp",ios::out|ios::app);
f<<str;
f.close();
}
int main() {
// 初始化winsock的环境
freopen("logs.txt","a",stdout);
WSADATA wd;
if (WSAStartup(MAKEWORD(2, 2), &wd) == SOCKET_ERROR) {
cout << "WSAStartup error:" << GetLastError() << endl;
return 0;
}
// 1.创建监听套接字
SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sListen == INVALID_SOCKET) {
cout << "socket error:" << GetLastError() << endl;
return 0;
}
// 2.绑定到ip与端口
sockaddr_in serverSockAddr;
serverSockAddr.sin_addr.S_un.S_addr = inet_addr("你的IP地址");
serverSockAddr.sin_port = htons(7999);
serverSockAddr.sin_family = AF_INET;
int len = sizeof(sockaddr_in);
if (bind(sListen, (SOCKADDR *) &serverSockAddr, len) == SOCKET_ERROR) {
cout << "bind error:" << GetLastError() << endl;
return 0;
}
// 3.监听套接字
if (listen(sListen, 5) == SOCKET_ERROR) {
cout << "listen error:" << GetLastError() << endl;
return 0;
}
// 4. select开始了
fd_set readSet;//定义一个读(接受消息)的集合
FD_ZERO(&readSet);//初始化集合
FD_SET(sListen, &readSet);
time_t now = time(NULL);
tm* tm_t = localtime(&now);
cout << "Start the server[time]year:" << tm_t->tm_year + 1900 << " month:" << tm_t->tm_mon + 1 << " day:" << tm_t->tm_mday << " hour:" << tm_t->tm_hour << " minute:" << tm_t->tm_min << " second:" << tm_t->tm_sec<<'\n';
while (true) {
fd_set tmpSet; // 定义一个临时的集合
FD_ZERO(&tmpSet); // 初始化集合
tmpSet = readSet; // 每次循环都是所有的套接字
// 利用select选择出集合中可以读写的多个套接字,有点像筛选
int ret = select(0, &tmpSet, NULL, NULL, NULL);//最后一个参数为NULL,一直等待,直到有数据过来
if (ret == SOCKET_ERROR) {
continue;
}
ofstream O("serverWin.dat");
// 成功筛选出来的tmpSet可以发送或者接收的socket
for (int i = 0; i < tmpSet.fd_count; ++i) {
//获取到套接字
SOCKET selectedSocket = tmpSet.fd_array[i];
// 接收到客户端的链接
if (selectedSocket == sListen) {
SOCKET c = accept(selectedSocket, NULL, NULL);
// fd_set集合最大值为64
if (readSet.fd_count < FD_SETSIZE) {
//往集合中添加客户端套接字
FD_SET(c, &readSet);
cout << c << " logged in.\n" << endl;
// 给客户端发送欢迎
char buf[100] = {0};
sprintf(buf, "hello from server", c);
send(c, buf, 100, 0);
} else {
cout << "max 64 clients for now." << endl;
}
} else {
// 接收客户端的数据
char buf[100] = {0};
ret = recv(selectedSocket, buf, 100, 0);
if (ret == SOCKET_ERROR || ret == 0) {
closesocket(selectedSocket);
FD_CLR(selectedSocket, &readSet);
cout << selectedSocket << "logged off.\n" << endl;
string str = usrname[selectedSocket];
str += " logged off.\n";
// save(str);
//msg.push_back(str);
if(match[usrname[selectedSocket]] != ""){
gotR[usrname[selectedSocket]] = false;
gotR[match[usrname[selectedSocket]]] = false;
chs[usrname[selectedSocket]] = 0;
chs[match[usrname[selectedSocket]]] = 0;
match[match[usrname[selectedSocket]]] = "";
match[usrname[selectedSocket]] = "";
}
isused[usrname[selectedSocket]] = 0;
usrname[selectedSocket] = "";
} else {
string op;
istringstream o(buf);
o>>op;
if(op == "--login"){
string name;
o>>name;
if(name == "" || isused[name])
Send(selectedSocket,"No");
else {
usrname[selectedSocket] = name,isused[name] = selectedSocket,Send(selectedSocket,"ok");
string str = usrname[selectedSocket];
str += " logged in.\n";
// save(str);
//msg.push_back(str);
}
} else if(op == "--join"){
wait.push_back(usrname[selectedSocket]);
isinque[usrname[selectedSocket]] = true;
while(wait.size()>=2){
string a,b;
a = wait[0];
wait.erase(wait.begin());
b = wait[0];
wait.erase(wait.begin());
match[a] = b;
match[b] = a;
gotR[usrname[selectedSocket]] = false;
gotR[match[usrname[selectedSocket]]] = false;
chs[usrname[selectedSocket]] = 0;
chs[match[usrname[selectedSocket]]] = 0;
// cerr<<"match:"<<match[a]<<' '<<match[b]<<'\n';
string str = a;
str += " and ";
str += b;
str += " began to fight\n";
save(str);
if(!wait.size())
break;
}
} else if(op == "--cancelJoin"){
// cerr<<"--cancelJoin\n";
for(auto it = wait.begin();it != wait.end();it++){
// cerr<<*it<<'\n';
if(*it == usrname[selectedSocket])
it = wait.erase(it),it--;
}
} else if(op == "--getWaitStatus"){
// cerr<<"name:"<<match[usrname[selectedSocket]]<<'\n';
if(match[usrname[selectedSocket]] != ""){
Send(selectedSocket,"OK!");
} else {
Send(selectedSocket,"Not yet");
}
} else if(op == "--getEnemyName"){
cerr<<usrname[selectedSocket]<<' '<<match[usrname[selectedSocket]]<<'\n';
if(match[usrname[selectedSocket]] != ""){
// cerr<<
Send(selectedSocket,match[usrname[selectedSocket]]);
} else {
Send(selectedSocket,"--Ohno");
}
} else if(op == "--getEnemyStatus"){
if(match[usrname[selectedSocket]] == ""){
Send(selectedSocket,"--Ohno");
}
if(chs[match[usrname[selectedSocket]]] != 0)
Send(selectedSocket,"ok");
else
Send(selectedSocket,"no");
} else if(op == "--rock"){
chs[usrname[selectedSocket]] = 1;
} else if(op == "--scissor"){
chs[usrname[selectedSocket]] = 2;
} else if(op == "--paper"){
chs[usrname[selectedSocket]] = 3;
} else if(op == "--getResult"){
if(!chs[usrname[selectedSocket]] || !chs[match[usrname[selectedSocket]]]){
Send(selectedSocket,"--wait");
// cerr<<"wait......\n";
continue;
}
int res = win(chs[usrname[selectedSocket]],chs[match[usrname[selectedSocket]]]);
cerr<<usrname[selectedSocket]<<' '<<match[usrname[selectedSocket]]<<' '<<res<<'\n';
if(res == -1)
Send(selectedSocket,"--draw");
if(res == 1)
Send(selectedSocket,"--win");
if(res == 0)
Send(selectedSocket,"--lose");
gotR[usrname[selectedSocket]] = true;
if(gotR[usrname[selectedSocket]]&&gotR[match[usrname[selectedSocket]]]){
string final = usrname[selectedSocket];
final += "'s choice is ";
final += hd[chs[usrname[selectedSocket]]];
final += " and ";
final += match[usrname[selectedSocket]];
final += "'s choice is ";
final += hd[chs[match[usrname[selectedSocket]]]];
final += ", so finally ";
if(res == -1){
final += "they were tied.\n";
} else {
if(res == 1)
final += usrname[selectedSocket];
if(res == 0)
final += match[usrname[selectedSocket]];
final += " winned.\n";
}
// save(final);
gotR[usrname[selectedSocket]] = false;
gotR[match[usrname[selectedSocket]]] = false;
chs[usrname[selectedSocket]] = 0;
chs[match[usrname[selectedSocket]]] = 0;
match[match[usrname[selectedSocket]]] = "";
match[usrname[selectedSocket]] = "";
}
} else if(op == "--conn"){
Send(selectedSocket,"fine");
}
cout << selectedSocket << " sent " << buf << endl;
}
}
}
}
// f.close();
// 关闭监听套接字
closesocket(sListen);
// 清理winsock环境
WSACleanup();
return 0;
}
#include<winsock2.h>//winsock2的头文件
#include<iostream>
#include<conio.h>
#include<bits/stdc++.h>
#define get char buf[300] = {0};recv(s, buf, 300, 0);
using namespace std;
string username;
string hd[4] = {"未出手\n","石头\n","剪刀\n","布\n"};
int win = 0,draw = 0,lose = 0,sum = 0;
//勿忘,链接dll的lib
#pragma comment(lib, "ws2_32.lib")
int Send(SOCKET s,string str){
char buf[300] = {0};
sprintf(buf, str.c_str());
return send(s, buf, 300, 0);
}
void savedata(){
ofstream o(username.c_str());
o<<win<<'\n'<<draw<<'\n'<<lose<<'\n'<<sum<<'\n';
o.close();
}
int main() {
//加载winsock2的环境
WSADATA wd;
if (WSAStartup(MAKEWORD(2, 2), &wd) != 0) {
cout << "WSAStartup error:" << GetLastError() << endl;
return 0;
}
//1.创建流式套接字
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET) {
cout << "socket error:" << GetLastError() << endl;
return 0;
}
//2.连接服务器
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(7999);
addr.sin_addr.S_un.S_addr = inet_addr("服务端IP地址");
int len = sizeof(sockaddr_in);
if (connect(s, (SOCKADDR *) &addr, len) == SOCKET_ERROR) {
cout << "connect error:" << GetLastError() << endl;
return 0;
}
//3接收服务端的消息
char buf[300] = {0};
recv(s, buf, 300, 0);
cout << buf << endl;
//3随时给服务端发消息
int ret = 0;
do {
while(1){
system("cls");
cout<<"请输入用户名!";
cin>>username;
string ss = "--login "+username;
Send(s,ss);
get;
// cerr<<"return:"<<buf<<'\n';
if(buf[0] != 'N')
break;
}
ifstream i(username.c_str());
if(!i.is_open()){
savedata();
} else{
i>>win>>draw>>lose>>sum;
i.close();
}
do{
ret = Send(s,"--conn");
get;
system("cls");
savedata();
cout<<"决斗\n\n你好,"<<username<<"!\n1、开始匹配!\n2、查看战绩\n3、帮助\n";
int choice;
cin>>choice;
if(choice == 1){
cout<<"开始匹配!按任意键取消!\n";
ret = Send(s,"--join");
while(1){
if(_kbhit()){
getch();
ret = Send(s,"--cancelJoin");
break;
}
ret = Send(s,"--getWaitStatus");
get;
string res = buf;
if(res == "OK!"){
bool isdo = false,isedo = false;
ret = Send(s,"--getEnemyName");
get;
string ename = buf;
if(ename == "--Ohno"){
cout<<"你的对手掉线了……";
break;
}
cout<<"匹配成功!你的对手为"<<ename<<'\n';
sum++;
Sleep(600);
int lastRe = time(0);
int you = 0;
while(1){
if(!_kbhit()){
if(time(0) - lastRe < 1)
continue;
system("cls");
ret = Send(s,"--getEnemyStatus");
get;
string ss = buf;
if(ss == "--Ohno"){
cout<<"你的对手掉线了!\n";
break;
}
if(ss=="ok")
isedo = true;
cout<<"你"<<(isdo?"出了\n":"没出\n");
cout<<"你的出手:"<<hd[you];
cout<<"你:"<<username<<(isdo?"已出手\n":"尚未出手\n");
cout<<"对手:"<<ename<<(isedo?"已出手\n":"尚未出手\n");
cout<<"\n\n你要出?(1=石头、2=剪刀、3=布)\n";
if(isdo && ss == "ok"){
ret = Send(s,"--getResult");
get;
string res = buf;
if(res != "--wait"){
system("cls");
// cerr<<res<<'\n';
if(res == "--draw")
cout<<"平局!\n",draw++;
if(res == "--win")
cout<<"胜利!\n",win++;
if(res == "--lose")
cout<<"失败!\n",lose++;
system("pause");
break;
}
}
lastRe = time(0);
} else if(!isdo) {
char ch = getch();
if(ch == '1')
ret = Send(s,"--rock"),you = 1;
else if(ch == '2')
ret = Send(s,"--scissor"),you = 2;
else if(ch == '3')
ret = Send(s,"--paper"),you = 3;
else
continue;
isdo = true;
lastRe = 0;
} else
getch(),lastRe = 0;
}
break;
}
}
}else if(choice == 2){
system("cls");
cout<<"决斗\n\n你好,"<<username<<"!\n在过去的"<<sum<<"场决斗中,你的战绩如下:\n胜:"<<win<<"场\n负:"<<lose<<"场\n平:"<<draw<<"场\n网络/其它故障:"<<sum-win-lose-draw<<"场\n";
system("pause");
} else if(choice == 3){
system("cls");
cout<<"你是弱智吗?";
system("pause");
}
Sleep(200);
}while (ret != SOCKET_ERROR && ret != 0);
} while (ret != SOCKET_ERROR && ret != 0);
cout<<"The server was closed\n";
//4.关闭监听套接字
closesocket(s);
//清理winsock2的环境
WSACleanup();
getchar();
getchar();
getchar();
getchar();
return 0;
}