zoukankan      html  css  js  c++  java
  • IOCP底层,支持超过15000个连接

    #pragma comment(lib,"ws2_32.lib")
    #include <winsock2.h>
    #include <stdio.h>
    //////////////////////////////////////////////////////////////////////////
    // 仅供测试软件用
    
    
    #define DATA_BUFSIZE 1024        // 接收缓冲区大小
    typedef enum{ IOSEND,IORECV,IOQUIT } IO_TYPE;
    typedef struct _SOCKET_INFORMATION {
    	OVERLAPPED Overlapped;
    	SOCKET        Socket;
    	IO_TYPE  IoType;
    	char                buffer[DATA_BUFSIZE];
    	WSABUF        DataBuf;
    	DWORD        BytesSEND;
    	DWORD        BytesRECV;
    } SOCKET_INFORMATION, * LPSOCKET_INFORMATION;
    DWORD   Flags = 0,
    Bytes = 0;
    DWORD WINAPI WorkThread(LPVOID CompletionPortID);
    DWORD WINAPI AcceptThread(LPVOID lpParameter)
    {
    	WSADATA wsaData;
    	HANDLE hCompPort;
    	DWORD ThreadID;
    	DWORD Ret;
    	if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
    	{
    		printf("WSAStartup failed with error %d
    ", Ret);
    		return FALSE;
    	}
    	if ((hCompPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL)
    	{
    		printf( "CreateIoCompletionPort failed with error: %d
    ", GetLastError());
    		return FALSE;
    	}
    	// 根据CPU个数来创建线程,以达到最佳性能
    	SYSTEM_INFO SystemInfo;
    	GetSystemInfo(&SystemInfo);
    	for(unsigned int i=0; i<SystemInfo.dwNumberOfProcessors*2; i++)
    	{
    		HANDLE ThreadHandle;
    		if ((ThreadHandle = CreateThread(NULL, 0, WorkThread, hCompPort, 0, &ThreadID)) == NULL)
    		{
    			printf("CreateThread() failed with error %d
    ", GetLastError());
    			return FALSE;
    		}
    		CloseHandle(ThreadHandle);
    	}
    	SOCKET ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, NULL, WSA_FLAG_OVERLAPPED);
    	SOCKADDR_IN ServerAddr;
    	ServerAddr.sin_family = AF_INET;
    	ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    	ServerAddr.sin_port = htons(7999);
    	bind(ListenSocket,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr));
    	listen(ListenSocket,100);
    	printf("listenning...
    ");
    	SOCKADDR_IN ClientAddr;
    	int addr_length=sizeof(ClientAddr);
    	while (TRUE)
    	{
    		LPSOCKET_INFORMATION  SI = new SOCKET_INFORMATION;
    		if ((SI->Socket = accept(ListenSocket,(SOCKADDR*)&ClientAddr, &addr_length)) != INVALID_SOCKET)
    		{
    			printf("accept ip:%s port:%d
    ",inet_ntoa(ClientAddr.sin_addr),ClientAddr.sin_port);
    			// 相关参数初始化
    			memset(&SI->Overlapped,0,sizeof(WSAOVERLAPPED));
    			memset(SI->buffer, 0, DATA_BUFSIZE);
    			SI->DataBuf.buf = SI->buffer;
    			SI->DataBuf.len = DATA_BUFSIZE;
    			SI->BytesRECV        = 0;
    			SI->BytesSEND        = 0;
    			SI->IoType           = IORECV;
    
    
    			if (CreateIoCompletionPort((HANDLE)SI->Socket, hCompPort, (DWORD)SI, 0) == NULL)
    			{
    				printf("CreateIoCompletionPort failed with error %d
    ", GetLastError());
    				return FALSE;
    			}
    			// 发出一个重叠IO请求
    			if(WSARecv(SI->Socket, &SI->DataBuf, 1, &Bytes, &Flags, &SI->Overlapped, NULL) == SOCKET_ERROR)
    			{
    				if(WSAGetLastError() != WSA_IO_PENDING)
    				{
    					printf("disconnect
    ");
    					closesocket(SI->Socket); 
    					delete SI;
    					continue;
    				}
    			}
    		}
    
    
    	}
    	return FALSE;
    }
    DWORD WINAPI WorkThread(LPVOID CompletionPortID)
    {
    	HANDLE hCompPort = (HANDLE)CompletionPortID;
    	while (TRUE)
    	{
    		DWORD BytesTransferred = 0;
    		LPSOCKET_INFORMATION SI = NULL;
    		LPWSAOVERLAPPED Overlapped = NULL;
    		// 线程进入线程池,等待被唤醒
    		if (GetQueuedCompletionStatus(hCompPort, &BytesTransferred, (LPDWORD)&SI, &Overlapped, INFINITE))
    		{
    			if (0 == BytesTransferred && IOQUIT != SI->IoType)
    			{
    				printf("disconnect
    ");
    				closesocket(SI->Socket); 
    				delete SI;
    				continue;
    			}
    			switch(SI->IoType)
    			{
    			case IORECV:
    				{
    					printf("%s 
    ", SI->buffer);
    					// 目前的功能是将接收到的数据原封不动的返回
    					SI->DataBuf.len = BytesTransferred;
    					SI->BytesRECV = BytesTransferred;
    					SI->IoType = IOSEND;
    					if (WSASend(SI->Socket, &SI->DataBuf, 1, &Bytes, Flags, &SI->Overlapped, NULL) == SOCKET_ERROR)
    					{
    						if(WSAGetLastError() != WSA_IO_PENDING)
    						{
    							printf("disconnect
    ");
    							closesocket(SI->Socket); 
    							delete SI;
    							continue;
    						}
    					}
    					break;
    				}
    			case IOSEND:
    				{
    					SI->BytesSEND += BytesTransferred;
    
    
    					//返回是否彻底,若未发完,接着发
    					if (SI->BytesSEND < SI->BytesRECV)
    					{
    						SI->DataBuf.buf += BytesTransferred; 
    						SI->DataBuf.len -= BytesTransferred; 
    						SI->IoType = IOSEND;
    						if (WSASend(SI->Socket, &SI->DataBuf, 1, &Bytes, Flags, &SI->Overlapped, NULL) == SOCKET_ERROR)
    						{
    							if(WSAGetLastError() != WSA_IO_PENDING)
    							{
    								printf("disconnect
    ");
    								closesocket(SI->Socket); 
    								delete SI;
    								continue;
    							}
    						}
    					}
    					else if (SI->BytesSEND > SI->BytesRECV)
    					{
    						printf("BytesSEND:%d > BytesRECV:%d
    ",SI->BytesSEND,SI->BytesRECV);
    						memset(SI->buffer, 0, DATA_BUFSIZE);
    						SI->BytesRECV = 0;
    						SI->BytesSEND = 0;
    
    
    						SI->IoType = IORECV;
    						SI->DataBuf.len = DATA_BUFSIZE;
    						SI->DataBuf.buf = SI->buffer;
    					}
    					else
    					{
    						memset(SI->buffer, 0, DATA_BUFSIZE);
    						SI->BytesRECV = 0;
    						SI->BytesSEND = 0;
    						SI->IoType = IORECV;
    						SI->DataBuf.len = DATA_BUFSIZE;
    						SI->DataBuf.buf = SI->buffer;
    						if (WSARecv(SI->Socket, &SI->DataBuf, 1, &Bytes, &Flags, &SI->Overlapped, NULL) == SOCKET_ERROR)
    						{
    							if(WSAGetLastError() != WSA_IO_PENDING)
    							{
    								printf("disconnect
    ");
    								closesocket(SI->Socket); 
    								delete SI;
    								continue;
    							}
    						}
    					}
    					break;
    				}
    
    
    			case IOQUIT:
    				{
    					// 让线程安全退出
    					return FALSE;
    					break;
    				}
    
    
    			default:
    				break;
    			}
    		}        
    	}        
    	return FALSE;
    }
    void main()   
    {
    	HANDLE hThreads = CreateThread(NULL, 0, AcceptThread, NULL, NULL, NULL); 
    
    
    	WaitForSingleObject(hThreads,INFINITE);
    	printf("exit
    ");
    	CloseHandle(hThreads);
    } 


  • 相关阅读:
    十分钟上手-搭建vue开发环境(新手教程)
    如何去掉bootstrap table中表格样式中横线竖线
    进阶攻略|前端最全的框架总结
    进阶攻略|前端完整的学习路线
    2018上半年GitHub上最热门的开源项目
    三分钟教你学会如何将密文解码成明文
    【前端图表】echarts实现散点图x轴时间轴
    IOS应用开发版本控制工具之Versions使用
    从零开始学ios开发(十七):Storyboards(上)
    ios按钮点击后翻转效果
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318574.html
Copyright © 2011-2022 走看看