网络基础编程_5.4聊天室-IOCP服务器
聊天室-IOCP服务器
main
创建完成端口内核对象(CreateIoCompletionPort)
获取核心数并创建线程(GetSystemInfo + CreateThread)
创建套接字并绑定接听(socket + bind + listen)
接收客户端并绑定IOCP(accept + CreateIoCompletionPort)
将客户端套接字添加到队列(vector.pushback)
投递一个客户端套接字的IO请求(WSARecv)
thread
从完成队列中获取完成的消息(GetQueuedCompletionStatus)
判断是否获取成功,如果成功就转发消息,投递一个新的IO请求
如果失败就将自己从客户端容器中删除
- #include <stdio.h>
- // 1. 包含必要的头文件和库, 必须位于 windows之前
- #include <WinSock2.h>
- #pragma comment(lib, "ws2_32.lib")
- #include <windows.h>
- #include <ws2tcpip.h>
- // 动态数组
- #include <vector>
- using namespace std;
- // 用于保存所有连接的客户端
- vector<SOCKET> ClientList;
- // 创建一个自定义的 OVERLAPPED 的结构,附加一些数据
- struct MyOverLapped
- {
- // 保留原始的重叠结构
- OVERLAPPED Overlapped;
- // 自己添加新的数据
- WSABUF WsaBuf;
- };
- // 工具函数,用于判断是否执行成功
- VOID CheckResult(BOOL Value, LPCWSTR ErrMsg)
- {
- // 如果 Value 非空,就表示执行成功
- if (Value == FALSE)
- {
- printf("ErrMsg: %ls\n", ErrMsg);
- system("pause"); ExitProcess();
- }
- }
- // 用于执行接收数据的线程
- DWORD WINAPI ThreadRoutine(LPVOID lpThreadParameter)
- {
- // 保存函数的执行结果
- BOOL Result = FALSE;
- // 保存实际的操作数量
- DWORD RealOper = ;
- // 定义完成键,作用是区分IO请求是谁发送的,在绑定的时候设置
- ULONG_PTR CompletKey = ;
- // 重叠 IO 结构
- MyOverLapped* pOverLapped = nullptr;
- // 获取 IOCP 内核对象
- HANDLE IoHandle = (HANDLE)lpThreadParameter;
- // 2. 在循环中不断的接收数据,如果返回值为 > 0 表示成功
- while (TRUE)
- {
- // 当有 IO 请求完成时,从中获取完成的信息,没有就休眠
- Result = GetQueuedCompletionStatus(
- IoHandle, // IOCP 内核对象
- &RealOper, // 实际操作数量
- &CompletKey, // 完成键
- (LPOVERLAPPED*)& pOverLapped, // 存放重叠结构
- INFINITE); // 等待时长
- // 3. 将当前的套接字关闭并从列表移除
- if (Result == FALSE && RealOper == )
- {
- for (int i = ; i < ClientList.size(); ++i)
- {
- // 找到当前对应的套接字
- if (ClientList[i] == (SOCKET)CompletKey)
- {
- // 收尾工作
- closesocket((SOCKET)CompletKey);
- printf("%08X 退出了聊天室\n", (SOCKET)CompletKey);
- ClientList.erase(ClientList.begin() + i);
- break;
- }
- }
- }
- else
- {
- // 转发给当前在线的除自己以外的所有客户端
- for (size_t i = ; i < ClientList.size(); ++i)
- {
- // 排除掉自己,不会发消息给自己
- if (ClientList[i] == (SOCKET)CompletKey)
- continue;
- // 直接转发消息
- send(ClientList[i], pOverLapped->WsaBuf.buf, pOverLapped->WsaBuf.len, );
- }
- // 释放堆空间的数据
- delete[] pOverLapped->WsaBuf.buf;
- delete pOverLapped;
- // 每一个异步 IO 操作都需要重叠结构
- MyOverLapped* OverLapped = new MyOverLapped{ };
- OverLapped->WsaBuf.len = 0x100;
- OverLapped->WsaBuf.buf = new char[0x100]{ };
- // 先投递一个接收的消息
- DWORD RealRecv = , Flags = ;
- WSARecv(
- (SOCKET)CompletKey, // 客户端套接字
- &OverLapped->WsaBuf, // 保存缓冲区和缓冲区的大小
- , // 缓冲区的个数
- &RealRecv, // 实际操作数
- &Flags, // 标志
- (OVERLAPPED*)OverLapped,// 重叠结构
- NULL); // 回调函数
- }
- }
- return ;
- }
- int main()
- {
- // [1] 创建一个完成端口内核对象,固定写法
- HANDLE IoHanlde = CreateIoCompletionPort(
- INVALID_HANDLE_VALUE, NULL, , );
- // [2] 获取当前 CPU 的数量
- SYSTEM_INFO SystemInfo = { };
- GetSystemInfo(&SystemInfo);
- // [3] 根据获取的 CPU 数量,创建线程
- for (int i = ; i < SystemInfo.dwNumberOfProcessors; ++i)
- CreateThread(NULL, NULL, ThreadRoutine, (LPVOID)IoHanlde, NULL, NULL);
- // 2. 初始化网络环境并判断是否成功[ 搜索信号(2G?3G?4G?) ]
- WSAData WsaData = { };
- if (!WSAStartup(MAKEWORD(, ), &WsaData))
- CheckResult(WsaData.wVersion == 0x0202, L"初始化网络环境失败");
- // 3. 创建套接字(IP+PORT) [ 买手机 ]
- SOCKET ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- CheckResult(ServerSocket != INVALID_SOCKET, L"套接字创建失败");
- // 4. 绑定套接字,提供IP和端口 (办手机卡)
- sockaddr_in ServerAddr = { };
- ServerAddr.sin_port = htons(0x1515); // 端口
- ServerAddr.sin_family = AF_INET; // 协议类型
- inet_pton(AF_INET, "127.0.0.1", &ServerAddr.sin_addr.S_un);
- BOOL Result = bind(ServerSocket, // 要绑定的套接字
- (SOCKADDR*)& ServerAddr, // 服务器的地址和IP对应的结构体
- sizeof(sockaddr_in)); // 必须要指定大小
- CheckResult(Result != SOCKET_ERROR, L"套接字绑定失败");
- // 5. 监听套接字 (开机,等待连接)
- // - 监听谁,最多等待多少个客户端的链接
- Result = listen(ServerSocket, SOMAXCONN);
- // 6. 循环等待客户端的连接(接电话)
- while (true)
- {
- // 接收客户端
- int dwSize = sizeof(sockaddr_in);
- sockaddr_in ClientAddr = { }; // 接收的客户端ip和端口
- SOCKET ClientSocket = accept(ServerSocket,
- (SOCKADDR*)&ClientAddr, &dwSize);
- // 添加到容器中
- printf("%08X 进入了聊天室\n", ClientSocket);
- ClientList.push_back(ClientSocket);
- // [4] 绑定套接字对象到 IOCP 句柄
- CreateIoCompletionPort((HANDLE)ClientSocket,
- // (完成键)会在接收到消息时,传入到线程函数中
- IoHanlde, (ULONG_PTR)ClientSocket, );
- // [5] 每一个异步 IO 操作都需要重叠结构
- MyOverLapped* OverLapped = new MyOverLapped{ };
- OverLapped->WsaBuf.len = 0x100;
- OverLapped->WsaBuf.buf = new char[0x100]{ };
- // [6] 先投递一个接收的消息
- DWORD RealRecv = , Flags = ;
- WSARecv(
- ClientSocket, // 客户端套接字
- &OverLapped->WsaBuf, // 保存缓冲区和缓冲区的大小
- , // 缓冲区的个数
- &RealRecv, // 实际操作数
- &Flags, // 标志
- (OVERLAPPED*)OverLapped,// 重叠结构
- NULL); // 回调函数
- }
- // 7. 关闭套接字执行清理工作
- closesocket(ServerSocket);
- // 8. 清理网络环境
- WSACleanup();
- system("pause");
- return ;
- }
网络基础编程_5.4聊天室-IOCP服务器的更多相关文章
- 网络编程TCP协议-聊天室
网络编程TCP协议-聊天室(客户端与服务端的交互); <span style="font-size:18px;">1.客户端发数据到服务端.</span> ...
- Linux应用程序设计之网络基础编程
1.TCP/IP协议概述 1.1.OSI参考模型及TCP/IP参考模型 OSI协议参考模型是基于国际标准化组织(ISO)的建议发展起来的,从上到下工分为7层:应用层,表示层,会话层,传输层,网络层,数 ...
- 网络编程-基于Websocket聊天室(IM)系统
目录 一.HTML5 - Websocket协议 二.聊天室(IM)系统的设计 2.1.使用者眼中的聊天系统 2.2.开发者眼中的聊天系统 2.3.IM系统的特性 2.4.心跳机制:解决网络的不确定性 ...
- 使用Android网络编程实现简易聊天室
在Java中我们可以利用socket编程实现聊天室,在Android中也一样,因为Android完全支持JDK本身的TCP.UDP网络通信API.我们可以使用ServerSocket.Socket来建 ...
- Java利用TCP编程实现简单聊天室
前言: 本文是我在学习尚学堂JAVA300集第二季网络编程部分仿照视频内容实现而成 具体可以去尚学堂官网观看视频学习 一.实现思路 实现聊天室的最核心部分就是JAVA的TCP网络编程. TCP 传输控 ...
- 手动搭建I/O网络通信框架4:AIO编程模型,聊天室终极改造
第一章:手动搭建I/O网络通信框架1:Socket和ServerSocket入门实战,实现单聊 第二章:手动搭建I/O网络通信框架2:BIO编程模型实现群聊 第三章:手动搭建I/O网络通信框架3:NI ...
- Linux C 网络编程——多线程的聊天室实现(server端)
server端的主要功能: 实现多用户群体聊天功能(此程序最多设定为10人.可进行更改),每一个人所发送的消息其它用户均能够收到.用户能够任意的增加或退出(推出以字符串"bye"实 ...
- Linux C 网络编程——多线程的聊天室实现(服务器端)
服务器端的主要功能: 实现多用户群体聊天功能(此程序最多设定为10人,可进行更改),每个人所发送的消息其他用户均可以收到.用户可以随意的加入或退出(推出以字符串"bye"实现),服 ...
- 【网络基础编程】第三节 C/S
学习地址: C语言中文网 - 实现迭代服务端和客户端 GNU - Closing a Socket 前面介绍的程序,不管Service 端还是 Client端,都有一个问题,就是处理完一个 accep ...
随机推荐
- Ubuntu 12.10终端Terminal快捷方式调用
1:使用快捷键:ctrl+alt+t 打开终端 2:在终端上右键,选“Lock to launcher” 这样就锁定在左侧了,需要用时,直接点就打开了.
- ubuntu1.8安装lnmp失败
兴致冲冲的安装好ubuntu1.8. 想安装lnmp,结果失败,失败,失败. 一遍由一遍,很痛苦. 每一遍都要半个小时,甚至更久. 等来的就是失败. 看日志也看不出头绪来. ============= ...
- poj-1655 Balancing Act(树的重心+树形dp)
题目链接: Balancing Act Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11845 Accepted: 4 ...
- UITabBarController简单介绍
一.简单介绍 UITabBarController和UINavigationController类似,UITabBarController也可以轻松地管理多个控制器,轻松完成控制器之间的切换,典型的例 ...
- 四:网络--NSURLConnection基本使用
一.NSURLConnection的常用类 (1)NSURL:请求地址 (2)NSURLRequest:封装一个请求,保存发给服务器的全部数据,包括一个NSURL对象,请求方法.请求头.请求体.... ...
- 利用http_load测试Web引擎性能
http_load是基于linux平台的性能测试工具,它体积非常小,仅100KB.它以并行复用的方式运行,可以测试web服务器的吞吐量与负载. 一.获得http_load httpd_load的官方站 ...
- python3中urllib的基本使用
urllib 在python3中,urllib和urllib2进行了合并,现在只有一个urllib模块,urllib和urllib2的中的内容整合进了urllib.request,urlparse整合 ...
- asp.net mvc4 不支持EF6
参考文章:http://www.cnblogs.com/zeusro/p/3403771.html http://q.cnblogs.com/q/40926/ 解决方法是 1.把EF6删除改用EF5. ...
- [知识积累]python3使用xlwt时写入文档字体颜色和边框样式
可借鉴的网址:https://www.programcreek.com/python/example/39979/xlwt.Alignment 可以直接通过pip安装xlwt 个人理解: xlwt中对 ...
- 洛谷 P3625 [APIO2009]采油区域【枚举】
参考:https://blog.csdn.net/FAreStorm/article/details/49200383 没有技术含量但是难想难写,枚举情况图详见参考blog懒得画了 bzoj蜜汁TTT ...