windows上 支持IOCP 的libevent TCP服务器该怎么个写法

windows上 支持IOCP 的libevent TCP服务器该怎么个写法,第1张

event_base_get_method函数能够获取对应的event_base使用的是哪个后端(即select、IOCP这些函数)。该函数返回一个字符串,字符串的内容就是select、poll、iocp这些后端的名字。 更正一下,由于在WIndows中,event_base_get_method函数返回的是win

如果用windows当服务器,IOCP很成熟所以选择C++。C#本身带有内存回收机制,对于某些类型的服务器需要自己管理内存回收,技术上没问题,听说过用C#当网页游戏服务器的成功案例。用C#的成本在这一行不算低(综合服务器,开发效率,招人难度等)。

Windows网络与通信程序设计(第2版) 王艳平  这本书写的非常好,我有本王艳平写的 windows程序设计,写得很好,我自己不做网络开发,就没有买网络的那本书!不过推荐你看看,真的很不错!

本书将编程方法、网络协议和应用实例有机结合起来,详细阐明Windows网络编程的各方面内容。本书首先介绍Windows平台上进行网络编程的基础知识,包括网络硬件、术语、协议、Winsock编程接口和各种I/O方法等;然后通过具体实例详细讲述当前流行的高性能可伸缩服务器设计、IP多播和Internet广播、P2P程序设计、原始套接字、SPI、协议驱动的开发和原始以太数据的发送、ARP欺骗技术、LAN和WAN上的扫描和侦测技术、个人防火墙与网络封包截获技术等;最后讲述IP帮助函数和E-mail的开发方法。  本书结构紧凑,内容由浅入

第1章 计算机网络基础 1

11 网络的概念和网络的组成 1

12 计算机网络参考模型 2

121 协议层次 2

122 TCP/IP参考模型 2

123 应用层(Application Layer) 3

124 传输层(Transport Layer) 3

125 网络层(Network Layer) 3

126 链路层(Link Layer) 4

127 物理层(Physical Layer) 4

13 网络程序寻址方式 4

131 MAC地址 4

132 IP地址 5

133 子网寻址 6

134 端口号 8

135 网络地址转换(NAT) 8

14 网络应用程序设计基础 10

141 网络程序体系结构 10

142 网络程序通信实体 11

143 网络程序开发环境 12

第2章 Winsock编程接口 13

21 Winsock库 13

211 Winsock库的装入和释放 13

212 封装CInitSock类 14

22 Winsock的寻址方式和字节顺序 14

221 Winsock寻址 14

222 字节顺序 16

223 获取地址信息 17

23 Winsock编程详解 20

231 Winsock编程流程 20

232 典型过程图 23

233 TCP服务器和客户端程序举例 24

234 UDP编程 26

24 网络对时程序实例 28

241 时间协议(Time Protocol) 28

242 TCP/IP实现代码 29

第3章 Windows套接字I/O模型 31

31 套接字模式 31

311 阻塞模式 31

312 非阻塞模式 31

32 选择(select)模型 32

321 select函数 32

322 应用举例 33

33 WSAAsyncSelect模型 36

331 消息通知和WSAAsyncSelect函数 36

332 应用举例 37

34 WSAEventSelect模型 40

341 WSAEventSelect函数 40

342 应用举例 42

343 基于WSAEventSelect模型的服务器设计 44

35 重叠(Overlapped)I/O模型 53

351 重叠I/O函数 53

352 事件通知方式 56

353 基于重叠I/O模型的服务器设计 56

第4章 IOCP与可伸缩网络程序 67

41 完成端口I/O模型 67

411 什么是完成端口(completion port)对象 67

412 使用IOCP的方法 67

413 示例程序 69

414 恰当地关闭IOCP 72

42 Microsoft扩展函数 72

421 GetAcceptExSockaddrs函数 73

422 TransmitFile函数 73

423 TransmitPackets函数 74

424 ConnectEx函数 75

425 DisconnectEx函数 76

43 可伸缩服务器设计注意事项 76

431 内存资源管理 76

432 接受连接的方法 77

433 恶意客户连接问题 77

434 包重新排序问题 78

44 可伸缩服务器系统设计实例 78

441 CIOCPServer类的总体结构 78

442 数据结构定义和内存池方案 82

443 自定义帮助函数 85

444 开启服务和停止服务 88

445 I/O处理线程 93

446 用户接口和测试程序 99

第5章 互联网广播和IP多播 100

51 套接字选项和I/O控制命令 100

511 套接字选项 100

512 I/O控制命令 102

52 广播通信 103

53 IP多播(Multicasting) 105

531 多播地址 105

532 组管理协议(IGMP) 105

533 使用IP多播 106

54 基于IP多播的组讨论会实例 110

541 定义组讨论会协议 110

542 线程通信机制 111

543 封装CGroupTalk类 111

544 程序界面 117

第6章 原始套接字 121

61 使用原始套接字 121

62 ICMP编程 121

621 ICMP与校验和的计算 121

622 Ping程序实例 124

623 路由跟踪 126

63 使用IP头包含选项 129

631 IP数据报格式 129

632 UDP数据报格式 131

633 原始UDP封包发送实例 133

64 网络嗅探器开发实例 134

641 嗅探器设计原理 135

642 网络嗅探器的具体实现 136

643 侦听局域网内的密码 138

65 TCP通信开发实例 140

651 创建一个原始套接字,并设置IP头选项 140

652 构造IP头和TCP头 140

653 发送原始套接字数据报 142

654 接收数据 146

第7章 Winsock服务提供者接口(SPI) 147

71 SPI概述 147

72 Winsock协议目录 148

721 协议特性 149

722 使用Winsock API函数枚举协议 150

723 使用Winsock SPI函数枚举协议 151

73 分层服务提供者(LSP) 153

731 运行原理 153

732 安装LSP 154

733 移除LSP 158

734 编写LSP 159

735 LSP实例 161

74 基于SPI的数据报过滤实例 165

75 基于Winsock的网络聊天室开发 171

751 服务端 171

752 客户端 171

753 聊天室程序的设计说明 172

754 核心代码分析 172

第8章 Windows网络驱动接口标准(NDIS)和协议驱动的开发 176

81 核心层网络驱动 176

811 Windows 2000及其后产品的网络体系结构 176

812 NDIS网络驱动程序 177

813 网络驱动开发环境 178

82 WDM驱动开发基础 181

821 UNICODE字符串 181

822 设备对象 181

823 驱动程序的基本结构 183

824 I/O请求包(I/O request packet,IRP)和I/O堆栈 183

825 完整驱动程序示例 186

826 扩展派遣接口 188

827 应用举例(进程诊测实例) 191

83 开发NDIS网络驱动预备知识 198

831 中断请求级别(Interrupt Request Level,IRQL) 198

832 旋转锁(Spin Lock) 198

833 双链表 199

834 封包结构 199

84 NDIS协议驱动 200

841 注册协议驱动 200

842 打开下层协议驱动的适配器 201

843 协议驱动的封包管理 202

844 在协议驱动中接收数据 203

845 从协议驱动发送封包 204

85 NDIS协议驱动开发实例 204

851 总体设计 204

852 NDIS协议驱动的初始化、注册和卸载 206

853 下层NIC的绑定和解除绑定 209

854 发送数据 217

855 接收数据 219

856 用户IOCTL处理 225

第9章 网络扫描与检测技术 233

91 网络扫描基础知识 233

911 以太网数据帧 233

912 ARP 234

913 ARP格式 236

914 SendARP函数 237

92 原始以太封包的发送 238

921 安装协议驱动 238

922 协议驱动用户接口 238

923 发送以太封包的测试程序 244

93 局域网计算机扫描 245

931 管理原始ARP封包 246

932 ARP扫描示例 249

94 互联网计算机扫描 253

941 端口扫描原理 253

942 半开端口扫描实现 254

95 ARP欺骗原理与实现 259

951 IP欺骗的用途和实现原理 259

952 IP地址冲突 260

953 ARP欺骗示例 261

第10章 点对点(P2P)网络通信技术 264

101 P2P穿越概述 264

102 一般概念 265

1021 NAT术语 265

1022 中转 265

1023 反向连接 266

103 UDP打洞 267

1031 中心服务器 267

1032 建立点对点会话 267

1033 公共NAT后面的节点 267

1034 不同NAT后面的节点 268

1035 多级NAT后面的节点 269

1036 UDP空闲超时 270

104 TCP打洞 271

1041 套接字和TCP端口重用 271

1042 打开点对点的TCP流 271

1043 应用程序看到的行为 272

1044 同步TCP打开 273

105 Internet点对点通信实例 273

1051 总体设计 273

1052 定义P2P通信协议 274

1053 客户方程序 275

1054 服务器方程序 287

1055 测试程序 291

第11章 核心层网络封包截获技术 294

111 Windows网络数据和封包过滤概述 294

1111 Windows网络系统体系结构图 294

1112 用户模式下的网络数据过滤 295

1113 内核模式下的网络数据过滤 296

112 中间层网络驱动PassThru 296

1121 PassThru NDIS中间层驱动简介 296

1122 编译和安装PassThru驱动 297

113 扩展PassThru NDIS IM驱动——添加IOCTL接口 297

1131 扩展之后的PassThru驱动(PassThruEx)概况 297

1132 添加基本的DeviceIoControl接口 298

1133 添加绑定枚举功能 302

1134 添加ADAPT结构的引用计数 307

1135 适配器句柄的打开/关闭函数 308

1136 句柄事件通知 315

1137 查询和设置适配器的OID信息 315

114 扩展PassThru NDIS IM驱动——添加过滤规则 323

1141 需要考虑的事项 323

1142 过滤相关的数据结构 324

1143 过滤列表 326

1144 网络活动状态 327

1145 IOCTL控制代码 328

1146 过滤数据 331

115 核心层过滤实例 339

第12章 Windows网络防火墙开发技术 342

121 防火墙技术概述 342

122 金羽(Phoenix)个人防火墙浅析 343

1221 金羽(Phoenix)个人防火墙简介 343

1222 金羽(Phoenix)个人防火墙总体设计 344

1223 金羽(Phoenix)个人防火墙总体结构 345

123 开发前的准备 345

1231 常量的定义 346

1232 访问规则 348

1233 会话结构 348

1234 文件结构 349

1235 UNICODE支持 355

124 应用层DLL模块 356

1241 DLL工程框架 356

1242 共享数据和IO控制 362

1243 访问控制列表ACL(Access List) 364

1244 查找应用程序访问权限的过程 367

1245 类的接口——检查函数 370

125 核心层SYS模块 373

126 主模块工程 375

1261 I/O控制类 375

1262 主应用程序类 377

1263 主对话框中的属性页 380

1264 主窗口类 381

127 防火墙页面 383

1271 网络访问监视页面 383

1272 应用层过滤规则页面 387

1273 核心层过滤规则页面 397

1274 系统设置页面 403

第13章 IP帮助函数 406

131 IP配置信息 406

1311 获取网络配置信息 406

1312 管理网络接口 408

1313 管理IP地址 412

132 获取网络状态信息 415

1321 获取TCP连接表 415

1322 获取UDP监听表 418

1323 获取IP统计数据 420

133 路由管理 427

1331 获取路由表 427

1332 管理特定路由 431

1333 修改默认网关的例子 432

134 ARP表管理 433

1341 获取ARP表 433

1342 添加ARP入口 434

1343 删除ARP入口 434

1344 打印ARP表的例子 434

135 进程网络活动监视实例 438

1351 获取通信的进程终端 438

1352 Netstate源程序代码 439

第14章 Email协议及其编程 444

141 概述 444

142 电子邮件介绍 445

1421 电子邮件Internet的地址 445

1422 Internet邮件系统 445

1423 电子邮件信头的结构及分析 446

143 SMTP原理 448

1431 SMTP原理分析 448

1432 SMTP工作机制 449

1433 SMTP命令码和工作原理 449

1434 SMTP通信模型 450

1435 SMTP的命令和应答 451

144 POP3协议原理 452

1441 POP3协议简介 452

1442 POP3工作原理 453

1443 POP3命令原始码 454

1444 POP3会话实例 459

145 实例分析与程序设计 460

1451 总界面设计 460

1452 SMTP客户端设计 461

1453 POP3客户端设计 473

恩。是的,你试着把Listen(sock,100)第二个参数设为100,相信出错10061会很少。
因为你的客户端是多线程的吧,而且并发执行,并发请求连接,这将会导致 服务端 接收请求队列 填满,从而拒绝了后来的客户端connect 我的QQ254904252,希望多多交流。

1同步阻塞IO(Blocking IO)

首先,解释一下这里的阻塞与非阻塞:阻塞IO,指的是需要内核IO *** 作彻底完成后,才返回到用户空间执行用户的 *** 作。阻塞指的是用户空间程序的执行状态。传统的IO模型都是同步阻塞IO。在Java中,默认创建的socket都是阻塞的。其次,解释一下同步与异步:同步IO,是一种用户空间与内核空间的IO发起方式。同步IO是指用户空间的线程是主动发起IO请求的一方,内核空间是被动接受方。异步IO则反过来,是指系统内核是主动发起IO请求的一方,用户空间的线程是被动接受方
 example:
   在Java应用程序进程中,默认情况下,所有的socket连接的IO *** 作都是同步阻塞IO(Blocking IO)。在阻塞式IO模型中Java应用程序从IO系统调用开始,直到系统调用返回,在这段时间内,Java进程是阻塞的。返回成功后,应用进程开始处理用户空间的缓存区数据。同步阻塞IO的具体流程,如图2-2所示。

举个例子,在Java中发起一个socket的read读 *** 作的系统调用,
流程大致如下:
(1)从Java启动IO读的read系统调用开始,
用户线程就进入阻塞状态。
(2)当系统内核收到read系统调用,就开始准备数据。一开始,数据可能还没有到达内核缓冲区(例如,还没有收到一个完整的socket数据包),这个时候内核就要等待。
(3)内核一直等到完整的数据到达,就会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存),然后内核返回结果(例如返回复制到用户缓冲区中的字节数)。
(4)直到内核返回后,用户线程才会解除阻塞的状态,重新运行起来。总之,阻塞IO的特点是:在内核进行IO执行的两个阶段,用户线程都被阻塞了。
阻塞IO的优点是:应用的程序开发非常简单;在阻塞等待数据期间,用户线程挂起。在阻塞期间,用户线程基本不会占用CPU资源。阻塞IO的缺点是:一般情况下,会为每个连接配备一个独立的线程;反过来说,就是一个线程维护一个连接的IO *** 作。在并发量小的情况下,这样做没有什么问题。但是,当在高并发的应用场景下,需要大量的线程来维护大量的网络连接,内存、线程切换开销会非常巨大。因此,基本上阻塞IO模型在高并发应用场景下是不可用的

2同步非阻塞IO(Non-blocking IO)
非阻塞IO,指的是用户空间的程序不需要等待内核IO *** 作彻底完成,可以立即返回用户空间执行用户的 *** 作,即处于非阻塞的状态,与此同时内核会立即返回给用户一个状态值。简单来说:阻塞是指用户空间(调用线程)一直在等待,而不能干别的事情;非阻塞是指用户空间(调用线程)拿到内核返回的状态值就返回自己的空间,IO *** 作可以干就干,不可以干,就去干别的事情。非阻塞IO要求socket被设置为NONBLOCK。强调一下,这里所说的NIO(同步非阻塞IO)模型,并非Java的NIO(New IO)库。
example:
socket连接默认是阻塞模式,在Linux系统下,可以通过设置将socket变成为非阻塞的模式(Non-Blocking)。使用非阻塞模式的IO读写,叫作同步非阻塞IO(None BlockingIO),简称为NIO模式。在NIO模型中,应用程序一旦开始IO系统调用,会出现以下两种情况:
(1)在内核缓冲区中没有数据的情况下,系统调用会立即返回,返回一个调用失败的信息。
(2)在内核缓冲区中有数据的情况下,是阻塞的,直到数据从内核缓冲复制到用户进程缓冲。复制完成后,系统调用返回成功,应用进程开始处理用户空间的缓存数据。
同步非阻塞IO的流程,如图2-3所示。

举个例子。发起一个非阻塞socket的read读 *** 作的系统调用,流程如下:
(1)在内核数据没有准备好的阶段,用户线程发起IO请求时,立即返回。所以,为了读取到最终的数据,用户线程需要不断地发起IO系统调用。
(2)内核数据到达后,用户线程发起系统调用,用户线程阻塞。内核开始复制数据,它会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存),然后内核返回结果(例如返回复制到的用户缓冲区的字节数)。
(3)用户线程读到数据后,才会解除阻塞状态,重新运行起来。也就是说,用户进程需要经过多次的尝试,才能保证最终真正读到数据,而后继续执行。同步非阻塞IO的特点:应用程序的线程需要不断地进行IO系统调用,轮询数据是否已经准备好,如果没有准备好,就继续轮询,直到完成IO系统调用为止。同步非阻塞IO的优点:每次发起的IO系统调用,在内核等待数据过程中可以立即返回。用户线程不会阻塞,实时性较好。同步非阻塞IO的缺点:不断地轮询内核,这将占用大量的CPU时间,效率低下。总体来说,在高并发应用场景下,同步非阻塞IO也是不可用的。一般Web服务器不使用这种IO模型。这种IO模型一般很少直接使用,而是在其他IO模型中使用非阻塞IO这一特性。在Java的实际开发中,也不会涉及这种IO模型。这里说明一下,同步非阻塞IO,可以简称为NIO,但是,它不是Java中的NIO,虽然它们的英文缩写一样,希望大家不要混淆。Java的NIO(NewIO),对应的不是四种基础IO模型中的NIO(NoneBlockingIO)模型,而是另外的一种模型,叫作IO多路复用模型(IOMultiplexing)。

3IO多路复用(IO Multiplexing)

即经典的Reactor反应器设计模式,有时也称为异步阻塞IO,Java中的Selector选择器和Linux中的epoll都是这种模型。
如何避免同步非阻塞IO模型中轮询等待的问题呢?这就是IO多路复用模型。在IO多路复用模型中,引入了一种新的系统调用,查询IO的就绪状态。在Linux系统中,对应的系统调用为select/epoll系统调用。通过该系统调用,一个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是内核缓冲区可读/可写),内核能够将就绪的状态返回给应用程序。随后,应用程序根据就绪的状态,进行相应的IO系统调用。目前支持IO多路复用的系统调用,有select、epoll等等。select系统调用,几乎在所有的 *** 作系统上都有支持,具有良好的跨平台特性。epoll是在Linux26内核中提出的,是select系统调用的Linux增强版本。在IO多路复用模型中通过select/epoll系统调用,单个应用程序的线程,可以不断地轮询成百上千的socket连接,当某个或者某些socket网络连接有IO就绪的状态,就返回对应的可以执行的读写 *** 作。举个例子来说明IO多路复用模型的流程。发起一个多路复用IO的read读 *** 作的系统调用,流程如下:
(1)选择器注册。在这种模式中,首先,将需要read *** 作的目标socket网络连接,提前注册到select/epoll选择器中,Java中对应的选择器类是Selector类。然后,才可以开启整个IO多路复用模型的轮询流程。
(2)就绪状态的轮询。通过选择器的查询方法,查询注册过的所有socket连接的就绪状态。通过查询的系统调用,内核会返回一个就绪的socket列表。当任何一个注册过的socket中的数据准备好了,内核缓冲区有数据(就绪)了,内核就将该socket加入到就绪的列表中。当用户进程调用了select查询方法,那么整个线程会被阻塞掉。
(3)用户线程获得了就绪状态的列表后,根据其中的socket连接,发起read系统调用,用户线程阻塞。内核开始复制数据,将数据从内核缓冲区复制到用户缓冲区。
(4)复制完成后,内核返回结果,用户线程才会解除阻塞的状态,用户线程读取到了数据,继续执行。

IO多路复用模型的特点:IO多路复用模型的IO涉及两种系统调用(SystemCall),另一种是select/epoll(就绪查询),一种是IO *** 作。IO多路复用模型建立在 *** 作系统的基础设施之上,即 *** 作系统的内核必须能够提供多路分离的系统调用select/epoll。和NIO模型相似,多路复用IO也需要轮询。负责select/epoll状态查询调用的线程,需要不断地进行select/epoll轮询,查找出达到IO *** 作就绪的socket连接。IO多路复用模型与同步非阻塞IO模型是有密切关系的。对于注册在选择器上的每一个可以查询的socket连接,一般都设置成为同步非阻塞模型。仅是这一点,对于用户程序而言是无感知的。IO多路复用模型的优点:与一个线程维护一个连接的阻塞IO模式相比,使用select/epoll的最大优势在于,一个选择器查询线程可以同时处理成千上万个连接(Connection)。系统不必创建大量的线程,也不必维护这些线程,从而大大减小了系统的开销。Java语言的NIO(NewIO)技术,使用的就是IO多路复用模型。在Linux系统上,使用的是epoll系统调用。IO多路复用模型的缺点:本质上,select/epoll系统调用是阻塞式的,属于同步IO。都需要在读写事件就绪后,由系统调用本身负责进行读写,也就是说这个读写过程是阻塞的。如何彻底地解除线程的阻塞,就必须使用异步IO模型。

4异步IO(Asynchronous IO)

异步IO,指的是用户空间与内核空间的调用方式反过来。用户空间的线程变成被动接受者,而内核空间成了主动调用者。这有点类似于Java中比较典型的回调模式,用户空间的线程向内核空间注册了各种IO事件的回调函数,由内核去主动调用
异步IO模型(AsynchronousIO,简称为AIO)。AIO的基本流程是:用户线程通过系统调用,向内核注册某个IO *** 作。内核在整个IO *** 作(包括数据准备、数据复制)完成后,通知用户程序,用户执行后续的业务 *** 作。在异步IO模型中,在整个内核的数据处理过程中,包括内核将数据从网络物理设备(网卡)读取到内核缓冲区、将内核缓冲区的数据复制到用户缓冲区,用户程序都不需要阻塞

举个例子。发起一个异步IO的read读 *** 作的系统调用,流程如下:
(1)当用户线程发起了read系统调用,立刻就可以开始去做其他的事,用户线程不阻塞。
(2)内核就开始了IO的第一个阶段:准备数据。等到数据准备好了,内核就会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存)。
(3)内核会给用户线程发送一个信号(Signal),或者回调用户线程注册的回调接口,告诉用户线程read *** 作完成了。
(4)用户线程读取用户缓冲区的数据,完成后续的业务 *** 作。异步IO模型的特点:在内核等待数据和复制数据的两个阶段,用户线程都不是阻塞的。用户线程需要接收内核的IO *** 作完成的事件,或者用户线程需要注册一个IO *** 作完成的回调函数。正因为如此,异步IO有的时候也被称为信号驱动IO。异步IO异步模型的缺点:应用程序仅需要进行事件的注册与接收,其余的工作都留给了 *** 作系统,也就是说,需要底层内核提供支持。理论上来说,异步IO是真正的异步输入输出,它的吞吐量高于IO多路复用模型的吞吐量。就目前而言,Windows系统下通过IOCP实现了真正的异步IO。而在Linux系统下,异步IO模型在26版本才引入,目前并不完善,其底层实现仍使用epoll,与IO多路复用相同,因此在性能上没有明显的优势。大多数的高并发服务器端的程序,一般都是基于Linux系统的。因而,目前这类高并发网络应用程序的开发,大多采用IO多路复用模型。大名鼎鼎的Netty框架,使用的就是IO多路复用模型,而不是异步IO模型。

本资料收集于Netty、Redis、Zookeeper高并发实战,希望大家购买正版图书地址:>

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zz/12693884.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-27
下一篇 2023-05-27

发表评论

登录后才能评论

评论列表(0条)

保存