通过select模型,可以在多个客户端连接的情况下,无需创建多个线程处理即单线程处理。 以下示例: Client端向Server端发送数据,Server端接收数据并输出。
Server.cpp
#include <iostream>
#include <windows.h>
using namespace std;
#pragma comment(lib, "Ws2_32.lib")
#define PORT_NO 6000
#define BACKLOG 10
int main(int argc, char* argv[])
{
WSADATA wsaData;
int ret;
WORD wVersionRequested = MAKEWORD(2, 2);
SOCKET sockSrv;
SOCKADDR_IN addrSrv, addrClient;
HANDLE hThread = NULL;
// 初始化Windows Socket------
ret = WSAStartup(wVersionRequested, &wsaData);
if (ret != 0)
{
cout << "WSAStartup() failed:" << WSAGetLastError() << endl;
return -1;
}
// 创建Socket------
sockSrv = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockSrv)
{
cout << "socket() failed:" << WSAGetLastError() << endl;
WSACleanup();
return -1;
}
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(PORT_NO);
// Bind Socket------
ret = bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
if (SOCKET_ERROR == ret)
{
cout << "bind() failed:" << WSAGetLastError() << endl;
closesocket(sockSrv);
WSACleanup();
return -1;
}
// 监听------
ret = listen(sockSrv, BACKLOG);
if (SOCKET_ERROR == ret)
{
cout << "listen() failed:" << WSAGetLastError() << endl;
closesocket(sockSrv);
WSACleanup();
return -1;
}
cout<< "Server started......" << endl;
// select------
//单线程实现多客户端处理
fd_set fdSocketAll; // 记录所有socket
FD_ZERO(&fdSocketAll);
FD_SET(sockSrv, &fdSocketAll);
while (1)
{
fd_set fdRead = fdSocketAll;
ret = select(0, &fdRead, NULL, NULL, NULL);
if (0 == ret) // 超时,由于timeout设为NULL,所有没有超时之说
{
cout << "over time..." << endl;
continue;
}
else if (ret > 0) // ok
{
#pragma region
for (int i=0; i<(int)fdRead.fd_count; ++i)
{
SOCKET sock = fdRead.fd_array[i];
if (sock == sockSrv) // 监听套接字接受到新连接
{
int len=sizeof(SOCKADDR);
SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrClient, &len);
if (INVALID_SOCKET == sockConn)
{
cout << "accept() failed:" << WSAGetLastError() << endl;
break;
}
cout << "接受到新连接:" << ::inet_ntoa(addrClient.sin_addr) << endl;
if (fdSocketAll.fd_count < FD_SETSIZE)
{
FD_SET(sockConn, &fdSocketAll);
}
else
{
cout << "Too much connections!" << endl;
closesocket(sockConn);
}
}
else // 有数据可读取
{
char recvBuffer[MAX_PATH] = {0};
ret = recv(sock, recvBuffer, sizeof(recvBuffer), 0);
if (ret == 0)
{
cout << "Connection has been gracefully closed." << endl;
FD_CLR(sock, &fdSocketAll);
closesocket(sock);
continue;
}
else if (ret == SOCKET_ERROR)
{
cout << "Connection has been closed ungracefully." << endl;
FD_CLR(sock, &fdSocketAll);
closesocket(sock);
continue;
}
cout << "Receive Data from Client:" << recvBuffer << endl;
}
}
#pragma endregion
}
else // error
{
cout << "select() failed:" << WSAGetLastError() << endl;
break;
}
}
// 清理资源------
for (int i=0; i<(int)fdSocketAll.fd_count; ++i)
{
closesocket(fdSocketAll.fd_array[i]);
}
WSACleanup();
cout << "exit..." << endl;
return 0;
}
Client.cpp
#include <iostream>
#include <windows.h>
using namespace std;
#pragma comment(lib, "Ws2_32.lib")
#define PORT_NO 6000
#define SRV_IP_ADDR "127.0.0.1"
int main(int argc, char* argv[])
{
int ret;
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
SOCKET sockClient;
SOCKADDR_IN addrSrv;
// 初始化Windows Socket------
ret = WSAStartup(wVersionRequested, &wsaData);
if (ret != 0)
{
cout << "WSAStartup() failed:" << WSAGetLastError() << endl;
return -1;
}
// 创建Socket------
sockClient = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockClient)
{
cout << "socket() failed:" << WSAGetLastError() << endl;
WSACleanup();
return -1;
}
addrSrv.sin_addr.S_un.S_addr = inet_addr(SRV_IP_ADDR);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(PORT_NO);
// 连接------
ret = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
if (SOCKET_ERROR == ret)
{
cout << "connect() failed:" << WSAGetLastError() << endl;
closesocket(sockClient);
WSACleanup();
return -1;
}
else
{
cout << "connect() successfully." << endl;
}
// 发送数据------
char sendBuf[MAX_PATH] = {0};
while (1)
{
cin.getline(sendBuf, sizeof(sendBuf));
if (strcmp(sendBuf, "exit") == 0)
{
break;
}
ret = send(sockClient, sendBuf, strlen(sendBuf)+1, 0);
if (SOCKET_ERROR == ret)
{
cout << "send() failed:" << WSAGetLastError() << endl;
closesocket(sockClient);
WSACleanup();
return -1;
}
}
// 清理资源-------
closesocket(sockClient);
WSACleanup();
cout << "exit..." << endl;
return 0;
}