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

972 篇文章 327 订阅
147 篇文章 46 订阅

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

 

#include <stdio.h>
#include <winsock2.h>   
#include <windows.h>
#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 <winsock2.h>
#include <stdio.h>
#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). 

 

       好, 先这样, 睡觉去。

 

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值