简易C/S 1.4

简易C/S 1.4将客户端升级为select

server每接入一个client通知给已连接的clients
client开启线程,可接收,可发送

server

#include <stdio.h>
#include <WinSock2.h>
#include <vector>
using namespace std;

#pragma comment(lib, "ws2_32.lib")

//DataPackage

enum CMD{
   CMD_LOGIN,
   CMD_LOGIN_RESULT,
   CMD_LOGOUT,
   CMD_LOGOUT_RESULT,
   CMD_NEW_USER_JOIN,
   CMD_ERROR
};

struct DataHeader{
   short cmd;			//命令
   short dataLength;	//数据长度
};

struct Login : public DataHeader{
   Login(){
   	this->cmd = CMD_LOGIN;
   	this->dataLength = sizeof(Login);
   }
   char userName[32];
   char password[32];
};

struct LoginResult : public DataHeader{
   LoginResult(){
   	this->cmd = CMD_LOGIN_RESULT;
   	this->dataLength = sizeof(LoginResult);
   	result = 0;
   }
   int result;
};

struct Logout : public DataHeader{
   Logout(){
   	this->cmd = CMD_LOGIN;
   	this->dataLength = sizeof(Logout);
   }
   char userName[32];
};

struct LogoutResult : public DataHeader{
   LogoutResult(){
   	this->cmd = CMD_LOGOUT_RESULT;
   	this->dataLength = sizeof(LogoutResult);
   	result = 0;
   }
   int result;
};

struct NewUserJoin :public DataHeader{
   NewUserJoin(){
   	dataLength = sizeof(NewUserJoin);
   	cmd = CMD_NEW_USER_JOIN;
   	sock = 0;
   }
   int sock;
};

vector<SOCKET> g_clients;

int process(SOCKET clientsock){

   char szRecv[1024] = {};
   //接受客户端数据
   int nLen = recv(clientsock, szRecv, sizeof(DataHeader), 0);
   DataHeader* header = (DataHeader*)szRecv;
   if (nLen <= 0){
   	printf("client <%d> exit.\n", clientsock);
   	return -1;
   }
   
   switch (header->cmd){
   case CMD_LOGIN:
   {
   	recv(clientsock, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
   	Login* login = (Login*)szRecv;
   	printf("recv <%d> cmd : CMD_LOGIN, dataLength : %d, userName=%s, password=%s\n", clientsock, login->dataLength, login->userName, login->password);
   	//用户名密码判断过程
   	LoginResult ret = {};
   	send(clientsock, (const char*)&ret, sizeof(LoginResult), 0);
   }
   	break;
   case CMD_LOGOUT:
   {
   	recv(clientsock, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
   	Logout* logout = (Logout*)szRecv;
   	printf("recv <%d> cmd : CMD_LOGOUT, dataLength : %d, userName=%s\n", clientsock, logout->dataLength, logout->userName);
   	//用户名密码判断过程
   	LogoutResult ret = {};
   	send(clientsock, (const char*)&ret, sizeof(LogoutResult), 0);
   }
   	break;
   default:
   {
   	DataHeader header = { CMD_ERROR, 0 };
   	send(clientsock, (const char*)&header, sizeof(DataHeader), 0);
   }
   	break;
   }

   return 0;
}


int main(int argc, char* argvp[])
{
   //初始化WSA
   WORD sockVersion = MAKEWORD(2, 2);
   WSADATA wsaData;
   if (WSAStartup(sockVersion, &wsaData) != 0){
   	return  -1;
   }

   //创建套接字
   SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (sock == INVALID_SOCKET){
   	printf("socket errot\n");
   	WSACleanup();
   	return -2;
   }

   //套接字结构体
   SOCKADDR_IN ser_addr;
   ser_addr.sin_family = AF_INET;
   ser_addr.sin_port = htons(8888);
   ser_addr.sin_addr.S_un.S_addr = INADDR_ANY;	//inet_addr("127.0.0.1");

   //绑定IP和端口
   if (bind(sock, (struct sockaddr*)&ser_addr, sizeof(ser_addr)) == SOCKET_ERROR){
   	printf("bind error\n");
   	closesocket(sock);
   	WSACleanup();
   	return -3;
   }

   //监听端口
   if (listen(sock, 5) == SOCKET_ERROR){
   	printf("listen error\n");
   	closesocket(sock);
   	WSACleanup();
   	return -4;
   }

#if 0
   //定义接收客户端的套接字
   SOCKET clientsock = INVALID_SOCKET;
   SOCKADDR_IN client_addr = {};
   int client_addr_len = sizeof(client_addr);
   //接受一个客户端连接
   clientsock = accept(sock, (struct sockaddr*)&client_addr, &client_addr_len);
   if (clientsock == INVALID_SOCKET){
   	printf("accept error\n");
   	closesocket(sock);
   	WSACleanup();
   	return -5;
   }
   printf("new client add, socket = %d, IP = %s\n",  clientsock, inet_ntoa(client_addr.sin_addr));
#endif
   while (true){

   	fd_set fdRead;
   	fd_set fdWrite;
   	fd_set fdExcept;

   	FD_ZERO(&fdRead);
   	FD_ZERO(&fdWrite);
   	FD_ZERO(&fdExcept);

   	FD_SET(sock, &fdRead);
   	FD_SET(sock, &fdWrite);
   	FD_SET(sock, &fdExcept);

   	for (size_t i = 0; i < g_clients.size(); ++i){
   		FD_SET(g_clients[i], &fdRead);
   	}
   
   	timeval t = { 1, 10 };
   	int ret = select(sock + 1, &fdRead, &fdWrite, &fdExcept, &t);
   	if (ret < 0){
   		printf("select error.\n");
   		break;
   	}

   	if (FD_ISSET(sock, &fdRead)){
   		FD_CLR(sock, &fdRead);
   		//定义接收客户端的套接字
   		SOCKET clientsock = INVALID_SOCKET;
   		SOCKADDR_IN client_addr = {};
   		int client_addr_len = sizeof(client_addr);
   		//接受一个客户端连接
   		clientsock = accept(sock, (struct sockaddr*)&client_addr, &client_addr_len);
   		if (clientsock == INVALID_SOCKET){
   			printf("accept error\n");
   			closesocket(sock);
   			WSACleanup();
   			return -5;
   		}
   		for (size_t i = 0; i < g_clients.size(); ++i){
   			NewUserJoin userJoin;
   			userJoin.sock = clientsock;
   			send(g_clients[i], (char*)&userJoin, sizeof(NewUserJoin), 0);
   		}
   		printf("new client add, socket = %d, IP = %s\n", clientsock, inet_ntoa(client_addr.sin_addr));
   		g_clients.push_back(clientsock);
   	}
   	for (size_t i = 0; i < fdRead.fd_count; ++i){
   		if (-1 == process(fdRead.fd_array[i])){
   			auto it = find(g_clients.begin(), g_clients.end(), fdRead.fd_array[i]);
   			if (it != g_clients.end()){
   				g_clients.erase(it);
   			}
   		}
   	}
   	
   	//printf("null\n");
   	
   }
   //关闭套接字
   for (size_t i = 0; i < g_clients.size(); ++i){
   	closesocket(g_clients[i]);
   }

   //清除window socket环境
   WSACleanup();
   getchar();
   return 0;
}

client

#include <stdio.h>
#include <WinSock2.h>
#include <thread>

#pragma comment(lib, "ws2_32.lib")

struct DataPackage{
	int age;
	char name[32];
};

enum CMD{
	CMD_LOGIN,
	CMD_LOGIN_RESULT,
	CMD_LOGOUT,
	CMD_LOGOUT_RESULT,
	CMD_NEW_USER_JOIN,
	CMD_ERROR
};

struct DataHeader{
	short cmd;			//命令
	short dataLength;	//数据长度
};

struct Login : public DataHeader{
	Login(){
		this->cmd = CMD_LOGIN;
		this->dataLength = sizeof(Login);
	}
	char userName[32];
	char password[32];
};

struct LoginResult : public DataHeader{
	LoginResult(){
		this->cmd = CMD_LOGIN_RESULT;
		this->dataLength = sizeof(LoginResult);
		result = 0;
	}
	int result;
};

struct Logout : public DataHeader{
	Logout(){
		this->cmd = CMD_LOGOUT;
		this->dataLength = sizeof(Logout);
	}
	char userName[32];
};

struct LogoutResult : public DataHeader{
	LogoutResult(){
		this->cmd = CMD_LOGOUT_RESULT;
		this->dataLength = sizeof(LogoutResult);
		result = 0;
	}
	int result;
};

struct NewUserJoin :public DataHeader{
	NewUserJoin(){
		dataLength = sizeof(NewUserJoin);
		cmd = CMD_NEW_USER_JOIN;
		sock = 0;
	}
	int sock;
};


int process(SOCKET sock){

	char szRecv[1024] = {};
	//接受客户端数据
	int nLen = recv(sock, szRecv, sizeof(DataHeader), 0);
	DataHeader* header = (DataHeader*)szRecv;
	if (nLen <= 0){
		printf("Disconnect to Server\n", sock);
		return -1;
	}

	switch (header->cmd){
	case CMD_NEW_USER_JOIN:
	{
		recv(sock, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
		NewUserJoin* userJoin = (NewUserJoin*)szRecv;
		printf("recv server cmd : CMD_NEW_USER_JOIN, dataLength : %d, NewUser<%d>\n", userJoin->dataLength, userJoin->sock);
	}
		break;
	case CMD_LOGIN_RESULT:
	{
		recv(sock, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
		LoginResult* loginRes = (LoginResult*)szRecv;
		printf("recv server cmd : CMD_LOGIN_RESULT, dataLength : %d\n", loginRes->dataLength);
	}
		break;
	case CMD_LOGOUT_RESULT:
	{
		recv(sock, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
		LogoutResult* logoutRes = (LogoutResult*)szRecv;
		printf("recv server cmd : CMD_LOGOUT_RESULT, dataLength : %d\n", logoutRes->dataLength);
	}
		break;
	}

	return 0;
}

bool g_bRun = true;

void cmdThread(SOCKET sock){
	//向服务器发送
	while (true){
		char cmdBuf[128] = {};
		printf("input cmd : ");
		memset(cmdBuf, 0, sizeof(cmdBuf));
		scanf("%s", cmdBuf);

		if (0 == strcmp(cmdBuf, "exit")){
			printf("exit\n");
			g_bRun = false;
			break;
		}
		else if (0 == strcmp(cmdBuf, "login")){
			Login login;
			strcpy(login.userName, "admin");
			strcpy(login.password, "admin123");
			send(sock, (const char*)&login, sizeof(Login), 0);
		}
		else if (0 == strcmp(cmdBuf, "logout")){
			Logout logout;
			strcpy(logout.userName, "admin");
			send(sock, (const char*)&logout, sizeof(Logout), 0);
		}
		else{
			printf("Cmd no support, please input again.\n");
		}
	}
}


int main(int argc, char* argvp[])
{
	//初始化WSA
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;

	//启动window socket2.0环境
	if (WSAStartup(sockVersion, &wsaData) != 0){
		return  -1;
	}

	//创建socket
	SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sock == INVALID_SOCKET){
		printf("socket error\n");;
		WSACleanup();
		return -1;
	}

	//连接服务器
	sockaddr_in _sin = {};
	_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	_sin.sin_family = AF_INET;
	_sin.sin_port = htons(8888);
	if (SOCKET_ERROR == connect(sock, (struct sockaddr*)&_sin, sizeof(_sin))){
		printf("connect error \n");
		closesocket(sock);
		WSACleanup();
		return -2;
	}

	//与服务器交互信息
	std::thread thr(cmdThread, sock);
	thr.detach();

	while (g_bRun){

		fd_set fdRead;
		FD_ZERO(&fdRead);
		FD_SET(sock, &fdRead);

		timeval t = { 1, 0 };
		int ret = select(sock, &fdRead, NULL, NULL, &t);
		if (ret < 0){
			printf("select error.\n");
			break;
		}

		if (FD_ISSET(sock, &fdRead)){
			FD_CLR(sock, &fdRead);
			if (-1 == process(sock)){
				printf("process error.\n");
				break;
			}
		}

#if 0
		char cmdBuf[128] = {};
		//向服务器发送
		printf("input cmd : ");
		memset(cmdBuf, 0, sizeof(cmdBuf));
		scanf("%s", cmdBuf);
		
		if (0 == strcmp(cmdBuf, "exit")){
			printf("exit\n");
			break;
		}
		else if (0 == strcmp(cmdBuf, "login")){
			Login login;
			strcpy(login.userName, "admin");
			strcpy(login.password, "admin123");
			send(sock, (const char*)&login, sizeof(Login), 0);

			LoginResult loginRet = {};
			recv(sock, (char*)&loginRet, sizeof(LoginResult), 0);
			printf("loginRet : %d\n", loginRet.result);
		}
		else if (0 == strcmp(cmdBuf, "logout")){
			Logout logout;
			strcpy(logout.userName, "admin");
			send(sock, (const char*)&logout, sizeof(Logout), 0);

			LogoutResult logoutRet = {};
			recv(sock, (char*)&logoutRet, sizeof(LogoutResult), 0);
			printf("logoutRet : %d\n", logoutRet.result);
		}
		else{
			printf("Cmd no support, please input again.\n");
		}
#endif

	}
	//关闭套接字
	closesocket(sock);

	//清除window socket环境
	WSACleanup();
	getchar();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值