基于非阻塞socket的多线程服务器的实现------一个服务器如何与多个客户端进行通信?

      我们首先来看服务端(涉及非阻塞socket和多线程):

#include 
#include    
#include 
#pragma comment(lib, "ws2_32.lib")
#define BUF_SIZE  100

sockaddr_in addrClient; // 为了让通信线程获取ip

// 通信线程
DWORD  WINAPI  CommThread(LPVOID  lp)  
{  
    SOCKET sClient = (SOCKET)(LPVOID)lp;  
 
	while(1)
	{    
		char buf[BUF_SIZE] = {0}; 
		int retVal = recv(sClient, buf, BUF_SIZE, 0);
		if(SOCKET_ERROR == retVal)   
		{   
			int err = WSAGetLastError();
			if(WSAEWOULDBLOCK == err) // 暂时没有数据
			{
				Sleep(100);
				continue;
			}
		}   

		// 输出客户端连接信息
		SYSTEMTIME st;
		GetLocalTime(&st);
		char sDateTime[100] = {0};
		sprintf(sDateTime, "%4d-%2d-%2d %2d:%2d:%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
		printf("%s, The client is [%s:%d]. Msg from client is : %s\n", sDateTime, inet_ntoa(addrClient.sin_addr), addrClient.sin_port, buf);   
		

		char msg[BUF_SIZE] = {0};  
		sprintf(msg, "Message received is : %s", buf); 
		while(1)
		{
			retVal = send(sClient, msg, strlen(msg), 0);  // 回显
			if(SOCKET_ERROR == retVal)   
			{   
				int err = WSAGetLastError();
				if(err == WSAEWOULDBLOCK)
				{
					Sleep(500);
					continue;
				}
			}

			break;
		}	  	
	}

    closesocket(sClient);   
}


int main()
{
	WSADATA wsd;   
    WSAStartup(MAKEWORD(2, 2), &wsd);   
    SOCKET sServer = socket(AF_INET, SOCK_STREAM, 0);   
   
	// 设置套接字为非阻塞模式
	int iMode = 1;
	ioctlsocket(sServer, FIONBIO, (u_long FAR*) &iMode);

    // 设置服务器套接字地址   
    SOCKADDR_IN addrServ;   
    addrServ.sin_family = AF_INET;   
    addrServ.sin_port = htons(8888);
    addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);    

    bind(sServer,(const struct sockaddr*)&addrServ, sizeof(SOCKADDR_IN));   
    
    listen(sServer, 10);   
      
	printf("Server start...\n");
	int addrClientlen = sizeof(addrClient);   
	while(1)
	{
		SOCKET sClient = accept(sServer, (sockaddr FAR*)&addrClient, &addrClientlen);   
		if(INVALID_SOCKET == sClient)   
		{   
			int err = WSAGetLastError();
			if(WSAEWOULDBLOCK == err)  // 无法立即完成非阻塞套接字上的操作
			{
				Sleep(100);
				continue;
			}
		} 

		// 创建通信线程
		CreateThread(NULL, NULL, CommThread, (LPVOID)sClient, 0, NULL);
	}

    // 释放套接字   
    closesocket(sServer);   
    WSACleanup();   

	getchar();
	return 0;
}
      不多解释。 先把服务端运行起来吧。


      下面, 我们来看看客户端:

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

int main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	wVersionRequested = MAKEWORD(2, 2);
	
	WSAStartup( wVersionRequested, &wsaData );

	SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);

	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(8888);
	connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));

	send(sockClient, "hello world", strlen("hello world") + 1, 0);
	char recvBuf[100] = {0};
	recv(sockClient, recvBuf, 100, 0);
	printf("%s\n", recvBuf);
	
	while(1);

	closesocket(sockClient);
	WSACleanup();

	return 0;
}
       然后同时运行多个客户端进程(请注意, 如果关掉某一个客户端进程, 则会引起一些异常, 为了简便起见, 本文就先不考虑这个情况了)。


       通过观察服务端和客户端的结果, 我们可以理解多线程服务器(非阻塞socket). 


       好, 先这样, 睡觉去。


你可能感兴趣的:(S1:,C/C++,s2:,软件进阶,s2:,网络编程,s2:,嵌入式,s2:,后台开发)