我是靠谱客的博主 整齐啤酒,这篇文章主要介绍【免杀前置课——Windows编程】十六、IOCP——输入输出完成端口( Input/Output Completion Port,IOCP) 、实现简易网络聊天室(多客户端 附代码)IOCP实现简易网络聊天室,现在分享给大家,希望可以做个参考。
IOCP
- IOCP
- 输入输出完成端口( Input/Output Completion Port,IOCP)
- 实现简易网络聊天室
- 服务器端
- 客户端
IOCP
输入输出完成端口( Input/Output Completion Port,IOCP)
是支持多个同时发生的异步I/0操作的应用程序编程接口,IOCP特别适合C/S模式网络服务器端模型。
因为,让每一个socket有一个线程负责同步(阻塞)数据处理,one-thread-per-client的缺点是:一是如果连入的客户多了,就需要同样多的线程;二是不同的socket 的数据处理都要线程切换的代价。
最佳线程数量=cpu内核数量2*
一个IOCP对象,在操作系统中可关联着多个Socket和(或)文件控制端。***IOCP对象内部有一个先进先出(FIFO)队列,用于存放IOCP所关联的输入输出端的服务请求完成消息。请求输入输出服务的进程不接收IO服务完成通知,而是检查IOCP的消息队列以确定I0请求的状态。(线程池中的>多个线程负责从IOCP 消息队列中取走完成通知并执行数据处理;如果队列中没有消息,那么线程阻塞挂起在该队列。***这些线程从而实现了负载均衡。
IOCP是一个内核对象,但是他是一个不需要安全属性的Windows内核对象。
实现简易网络聊天室
服务器端
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106#include<WinSock2.h> #include<Windows.h> #include<iostream> #include<ws2tcpip.h> #pragma comment(lib,"ws2_32.lib") #include<vector> using std::vector; vector<SOCKET> clientList;//保存多个线程的客户端 typedef struct _MY_OVERLAPPED { OVERLAPPED overLapped; WSABUF wsaBuf; }_MY_OVERLAPPED, * LPMY_OVERLAPPED; DWORD WINAPI revcMessage(LPVOID param) { BOOL result=FALSE; DWORD lpNumberOfBytesTransferred=0; ULONG_PTR client = 0; LPMY_OVERLAPPED lpOverLapped = NULL; DWORD flag = 0; //从IOCP队列中取出数据 while (true) { result = GetQueuedCompletionStatus((HANDLE)param, &lpNumberOfBytesTransferred, &client, (LPOVERLAPPED*) & lpOverLapped, INFINITE); if (lpNumberOfBytesTransferred>0&&result)//若当前客户端未断开连接 { for (int i = 0; i < clientList.size(); i++)//遍历进程中的每一个客户端线程 { if (client != clientList[i])//判断是不是当前线程发的消息,若不是则发送给每个客户端 { send(clientList[i], lpOverLapped->wsaBuf.buf, lpOverLapped->wsaBuf.len, 0); } } //清空OVERLAPPED memset(&lpOverLapped->overLapped, 0, sizeof(OVERLAPPED)); //清空缓冲区 memset(lpOverLapped->wsaBuf.buf, 0, 0x100); WSARecv(client, &lpOverLapped->wsaBuf, 1, &lpNumberOfBytesTransferred, &flag,(LPWSAOVERLAPPED)lpOverLapped,NULL); } else { for (int i = 0; i < clientList.size(); i++) { if (clientList[i] == client)//判断哪一个客户端线程断开了连接 { printf("客户端%u断开了连接n", clientList[i]); closesocket(clientList[i]); clientList.erase(clientList.begin() + i); } } } } return 0; } int main() { //创建IOCP对象 HANDLE hiocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); //获取CPU内核数量 SYSTEM_INFO sysInfo{ 0 }; GetNativeSystemInfo(&sysInfo); for (int i = 0; i < sysInfo.dwNumberOfProcessors*2; i++)//获取CPU内核数量*2是因为在CPU数量*2时是最佳线程数量 { //创建线程实现并发通信 CreateThread(NULL, NULL, revcMessage, (LPVOID)hiocp, NULL, NULL); } //1、初始化网络环境 WSADATA data{ 0 }; WSAStartup(MAKEWORD(2,2), &data); //2、创建Socket SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//用IPv4地址协议簇,TCP连接 //3、指定IP地址和端口号 sockaddr_in serverAddr{ 0 }; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(7777); inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);//InetPton函数将标准文本表示形式的 IPv4 或 IPv6 互联网网络地址转换为数字二进制形式 //printf("%sn", serverAddr.sin_addr); bind(server, (SOCKADDR*)&serverAddr, sizeof(serverAddr));//绑定函数将本地地址与套接字相关联。 //4、监听 listen(server, SOMAXCONN); //5、接受会话 sockaddr_in clientAddr{ 0 }; int size = sizeof(clientAddr); while (1) { SOCKET client = accept(server, (SOCKADDR*)&clientAddr, &size);//绑定将监听地址与套接字 clientList.push_back(client); //将SOCKET关联到IOCP CreateIoCompletionPort((HANDLE)client, hiocp, client, 0); LPMY_OVERLAPPED lpOverLapped = new _MY_OVERLAPPED{ 0 }; lpOverLapped->wsaBuf.len = 0x100; lpOverLapped->wsaBuf.buf = new char[0X100]; DWORD realRead = 0; DWORD flag = 0; //接受消息 WSARecv(client, &lpOverLapped->wsaBuf, 1, &realRead,& flag,(LPWSAOVERLAPPED)lpOverLapped, NULL); } closesocket(server); return 0; }
客户端
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53#include<WinSock2.h> #include<Windows.h> #include<iostream> #include<ws2tcpip.h> #pragma comment(lib,"ws2_32.lib") DWORD WINAPI revcMessage(LPVOID param) { SOCKET client = (SOCKET)param; char buff[0x100]{ 0 }; while (recv(client, buff, 0x100, 0) > 0) { printf("%sn", buff); } return 0; } int main() { //1、初始化网络环境 WSADATA data{ 0 }; WSAStartup(MAKEWORD(2, 2), &data); //2、创建Socket SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//用IPv4地址协议簇,TCP连接 //3、指定IP地址和端口号 sockaddr_in serverAddr{ 0 }; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(7777); inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);//InetPton函数将标准文本表示形式的 IPv4 或 IPv6 互联网网络地址转换为数字二进制形式 //4、连接 int result = connect(client, (SOCKADDR*)&serverAddr, sizeof(serverAddr)); if (result) { printf("连接服务器失败n"); } HANDLE hThread = CreateThread(NULL, NULL, revcMessage, (LPVOID)client, NULL, NULL); char buff[0x100]{ 0 }; while (scanf_s("%s",buff,0x100) && strcmp(buff,"exit"))//接受用户输入 { send(client, buff, strlen(buff) + 1, 0); } closesocket(client); CloseHandle(hThread); /*send(client, "我有话说n", 8, 0); char buff[0x100]{ 0 }; recv(client, buff, 0x100, 0); printf("server:%s", buff); system("pause");*/ return 0; }
最后
以上就是整齐啤酒最近收集整理的关于【免杀前置课——Windows编程】十六、IOCP——输入输出完成端口( Input/Output Completion Port,IOCP) 、实现简易网络聊天室(多客户端 附代码)IOCP实现简易网络聊天室的全部内容,更多相关【免杀前置课——Windows编程】十六、IOCP——输入输出完成端口(内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复