signed

QiShunwang

“诚信为本、客户至上”

windows 使用select实现多个客户端连入服务器

2021/6/3 17:24:27   来源:

服务端code

#include <winsock2.h>
#include <iostream>
#include <string.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable :4996)
const int DEFAULT_PORT = 8000;
#define SIZE 32
#define IP   "192.168.1.32"
#define PORT 8000
#define LISTENNUM 5
int initSocket();
int InitPlatform();
int main(int argc, char* argv[])
{
	int socketID = 0, maxFd = 0, ret = 0, newID = 0;
	int addrLength = 0;
	fd_set readFds;
	struct sockaddr_in addr;
	char buf[SIZE] = { 0 };
	InitPlatform();
	socketID = initSocket();
	if (0 > socketID)
	{
		printf("socket init error\r\n");
		return ERROR;
	}
	printf("init socket success\r\n");

	addrLength = sizeof(addr);
	maxFd = socketID;
	FD_ZERO(&readFds);
	FD_SET(socketID, &readFds);

	while (1)
	{
		fd_set tmp = readFds;
		ret = select(maxFd + 1, &tmp, NULL, NULL, NULL);
		printf("-------------------------\n");
		if (0 > ret)
		{
			perror("select error");
			return ERROR;
		}
		else if (0 == ret)
		{
			printf("select time out\r\n");
		}
		else
		{
			int i = 0;
			for (i = 0; i <= maxFd; i++)
			{
				if (FD_ISSET(i, &tmp))
				{
					/*如果是客户端发起的新连接,则该条件成立*/
					if (i == socketID)
					{
						memset(&addr, 0, addrLength);
						newID = accept(socketID, (struct sockaddr*)&addr, &addrLength);
						printf("i = %d, newID = %d\n", i, newID);
						if (0 > newID)
						{
							perror("accept error");
							return ERROR;
						}
						printf("client %d connected, IP=%s,port=%u\r\n", newID, (char*)inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
						FD_SET(newID, &readFds);
						if (newID > maxFd)
						{
							maxFd = newID;
						}
						continue;
					}
					/*以下则是对已经成功连接的处理*/
					memset(buf, 0, SIZE);
					ret = recv(i, buf, SIZE - 1, 0);
					if (0 > ret)
					{
						perror("recv error");
						closesocket(i);
						FD_CLR(i, &readFds);
						printf("client %d closed\r\n", i);
					}
					else if (0 == ret)
					{
						closesocket(i);
						FD_CLR(i, &readFds);
						printf("client %d closed\r\n", i);
					}
					else
						printf("client %d said:%s\r\n", i, buf);
				}
			}
		}
	}
	closesocket(socketID);
	WSACleanup();
}


int InitPlatform()
{
	WORD	wVersionRequested;
	WSADATA wsaData;
	int		err;
	wVersionRequested = MAKEWORD(2, 2);//create 16bit data
	err = WSAStartup(wVersionRequested, &wsaData);	//load win socket
	if (err != 0)
	{
		cout << "Load WinSock Failed!";
		return -1;
	}
	return 0;
}

int initSocket()
{
	int socketID = 0;
	int addrLength = 0;
	int flag = 1;
	struct sockaddr_in addr;

	//创建socket
	socketID = socket(AF_INET, SOCK_STREAM, 0);
	if (socketID < 0)
	{
		perror("socket error");
		return ERROR;
	}
	/*TIME_WAIT问题*/
	if (setsockopt(socketID, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(flag)) == -1)
	{
		perror("setsockopt");
		return ERROR;
	}
	//bind
	addrLength = sizeof(addr);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = INADDR_ANY;
	if (0 > bind(socketID, (struct sockaddr*)&addr, addrLength))
	{
		perror("bind error");
		return ERROR;
	}
	//listen
	if (0 > listen(socketID, LISTENNUM))
	{
		perror("listen error");
		return ERROR;
	}
	return socketID;
}

客户端code

#include <winsock2.h>
#include <iostream>
#include <string.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable :4996)
#define SIZE 32
#define IP   "192.168.1.32"
#define PORT 8000
#define LISTENNUM 5
int main()
{
	WSADATA wsa;
	int socketID = 0, addrLength = 0, ret = 0;
	struct sockaddr_in addr;
	char buf[SIZE] = { 0 };
	int err = WSAStartup(MAKEWORD(2, 2), &wsa);	//初始化WS2_32.DLL
	if (err != 0)
	{
		cout << "Load WinSock Failed!";
		return -1;
	}
	/*创建套接字*/
	socketID = socket(AF_INET, SOCK_STREAM, 0);
	if (socketID < 0)
	{
		perror("socket error");
		return -1;
	}
	/*设定要连接的IP/PORT*/
	addrLength = sizeof(addr);
	memset(&addr, 0, addrLength);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = inet_addr(IP);

	/*发送连接请求*/
	ret = connect(socketID, (const struct sockaddr*)(&addr), addrLength);
	if (ret < 0)
	{
		perror("connect error");
		closesocket(socketID);
		return -1;
	}
	printf("connect success\r\n");
	while (1)
	{
		fgets(buf, SIZE - 1, stdin);
		ret = send(socketID, buf, strlen(buf), 0);
		if (ret < 0)
		{
			perror("send error");
			closesocket(socketID);
			return -1;
		}
		/*打印发送的消息以及字节数*/
		printf("send success %s,ret = %d\n", buf, ret);
		if (strncmp(buf, "quit", 4) == 0)
		{
			break;
		}
	}
	/*关闭套接字*/
	closesocket(socketID);
	return 0;
}

先运行服务端:

init socket success

此时开始运行客户端,客户端显示:

connect success
hkjkjl
send success hkjkjl
,ret = 7

此时的服务端显示:

init socket success
-------------------------
i = 264, newID = 272
client 272 connected, IP=192.168.1.32,port=59783
-------------------------
client 272 said:hkjkjl

在发起一个客户端连接:

connect success
dadasdasdad
send success dadasdasdad
,ret = 12

此时服务端显示:

init socket success
-------------------------
i = 264, newID = 272
client 272 connected, IP=192.168.1.32,port=59783
-------------------------
client 272 said:hkjkjl

-------------------------
i = 264, newID = 196
client 196 connected, IP=192.168.1.32,port=60043
-------------------------
client 196 said:dadasdasdad