概述
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内核对象。
实现简易网络聊天室
服务器端
#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;
}
客户端
#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——输入输出完成端口( Input/Output Completion Port,IOCP) 、实现简易网络聊天室(多客户端 附代码)IOCP实现简易网络聊天室所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复