实现UDP IOCP心得-zt

http://h-lm.spaces.live.com/blog/cns!C523F565A10E3B66!824.entry

2008/11/11
实现UDP IOCP心得
当前许多资料都是介绍TCP的IOCP的实现,UDP的较少。
 
1.很多人在讨论UDP是否需要IOCP。
通宵奋战,搞定UDP+IOCP
     总算是没有白费时间,搞定了UDP+IOCP。原来的程序采用的是多线程+阻塞的变种,效率一直不如意。本来想一开始就用IOCP的,但是在网上查阅资料的时候看到讨论说UDP不需要用IOCP的,自己想想也觉得有点道理。于是就用最简单的多线程+阻塞来实现了数据采集。后来测试的时候效率一直不如意,更改为IOCP模型时思路错了,一直更改不成功。昨晚突然想到了问题所在,一下就把UDP+IOCP实现了。呵呵。
      总算是小有收获,工作线程更改用户界面的问题也解决了,数据采集效率也还过得去了,相关测试程序都可以勉强运转了,又恢复了些许信心了。感觉是度过了一个黎明前的黑夜了,只是不知道还有多少个更黑的夜晚需要经历。
 
我的实现还没有进行测试,之后再附上。
 
2.TCP的IOCP是在Accept之后,将Accept创建的套接字与完成端口绑定,而在UDP中,则是把WSASocket或Socket创建的套接字与完成端口绑定。
在实现UDP IOCP时,可以参考已有的TCP IOCP代码,例如 http://www.cppblog.com/niewenlong/archive/2007/08/17/30224.html
另外 http://www.codeproject.com/KB/IP/iocp-multicast-udp.aspx 可供下的源码中的客户端代码是UDP IOCP实现
 
3.以下数据结构非常重要。
typedef struct _PER_IO_OPERATION_DATA
{
    OVERLAPPED Overlapped;
    WSABUF DataBuff;
    char Buff[24];
    BOOL OperationType;
}PER_IO_OPERATION_DATA,* LPPER_IO_OPERATION_DATA;
因为在UDP中每次RecvFrom获WSARecvFrom会传回UDP数据来源的IP,因此可以将以上数据结构修改成:
typedef struct _PER_IO_OPERATION_DATA
{
    OVERLAPPED Overlapped;
    WSABUF DataBuff;
    char Buff[24];
    unsigned long recvBytes;      //存储接收到的字节数
    SOCKADDR_IN remoteAddr; //存储数据来源IP地址
    int remoteAddrLen;              //存储数据来源IP地址长度
}PER_IO_OPERATION_DATA,* LPPER_IO_OPERATION_DATA;
 
4.实现过程
创建LPPER_IO_OPERATION_DATA数据结构并进行初始化(初始化很重要)
    LPPER_IO_OPERATION_DATA ioperdata;
    ioperdata = (LPPER_IO_OPERATION_DATA)malloc(sizeof(PER_IO_OPERATION_DATA));
    memset(&(ioperdata->Overlapped), 0, sizeof(OVERLAPPED));
   
    (ioperdata->DataBuff).len = 24;
    (ioperdata->DataBuff).buf = ioperdata->Buff;
    ioperdata->recvBytes = 24;
    ioperdata->remoteAddrLen = sizeof(ioperdata->remoteAddr);
创建完成端口
hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);  
创建UDP socket
udpSocket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
绑定UDP Socket
bind(udpSocket, (SOCKADDR*) & addr, sizeof(SOCKADDR_IN));
将完成端口与UDP Socket绑定
    CreateIoCompletionPort(
        (HANDLE)udpSocket,
        hCompletionPort,
        (DWORD)udpSocket,
        5
    );
根据CPU数量*2+2的原则创建工作者线程------- ------- --------------一直循环
CreateWorkers(m_dwThreads)
接收数据                                                                          获得当前完成状态  GetQueuedCompletionStatus(
WSARecvFrom(                                                                                     ComPort,
                udpSocket,                                                                          &BytesTransferred,
                &(ioperdata->DataBuff),                                                         (LPDWORD) & nSocket,
                1,                                                                                       (LPOVERLAPPED *) & PerIoData,
                &(ioperdata->recvBytes),                                                        INFINITE   );                   
                &flags,                                                           
                (SOCKADDR*) & (ioperdata->remoteAddr),                                
                &(ioperdata->remoteAddrLen),                
                &(ioperdata->Overlapped),                                
                NULL);                                                            处理接收到的数据
                                                                                    继续执行投递操作(类同接收数据操作)
 
5.WSAGetLastError错误代码
通过WSAGetLastError的信息来测试程序中出现的问题,常见的错误有10055、10014、6等,最主要的是变量的初始化。
 
1- 不要为每个小数据包发送一个IOCP请求,这样很容易耗尽IOCP的内部队列.....从而产生10055错误.
2- 不要试图在发送出IOCP请求之后,收到完成通知之前修改请求中使用的数据缓冲的内容,因为在这段时间,系统可能会来读取这些缓冲.
 3- 为了避免内存拷贝,可以尝试关闭SOCKET的发送和接收缓冲区,不过代价是,你需要更多的接收请求POST到一个数据流量比较大的SOCKET,从而保证系统一直可以找到BUFFER来收取到来的数据.
4- 在发出多个接收请求的时候,如果你的WORKTHREAD不止一个,一定要使用一些手段来保证接收完成的数据按照发送接收请求的顺序处理,否则,你会遇到数据包用混乱的顺序排列在你的处理队列里.....
5- 说起工作线程, 最好要根据MS的建议, 开 CPU个数*2+2 个, 如果你不了解IOCP的工作原理的话.
6- IOCP的工作线程是系统优化和调度的, 自己就不需要进行额外的工作了.如果您自信您的智慧和经验超过MS的工程师, 那你还需要IOCP么....
7-发出一个Send请求之后,就不需要再去检测是否发送完整,因为iocp会帮你做这件事情,有些人说iocp没有做这件事情,这和iocp的高效能是相悖的,并且我做过的无数次测试表明,Iocp要么断开连接,要么就帮你把每个发送请求都发送完整。
8- 出现数据错乱的时候,不要慌,要从多线程的角度检查你的解析和发送数据包的代码,看看是不是有顺序上的问题。
9- 当遇到奇怪的内存问题时,逐渐的减少工作线程的数量,可以帮你更快的锁定问题发生的潜在位置。
10-同样是遇到内存问题时,请先去检查你的客户端在服务器端内部映射对象的释放是否有问题。而且要小心的编写iocp完成失败的处理代码,防止引用一个错误的内部映射对象的地址。
11- overlapped对象一定要保存在持久的位置,并且不到操作完成(不管成功还是失败)不要释放,否则可能会引发各种奇怪的问题。
12- IOCP的所有工作都是在获取完成状态的那个函数内部进行调度和完成的,所以除了注意工作线程的数量之外,还要注意,尽量保持足够多的工作线程处在获取完成状态的那个等待里面,这样做就需要减少工作线程的负担,确保工作线程内部要处理费时的工作。(我的建议是工作线程和逻辑线程彻底区分开)
13- 刚刚想起来,overlapped对象要为每次的send和recv操作都准备一个全新的,不能图方便重复利用。
14- 尽量保持send和recv的缓冲的大小是系统页面大小的倍数,因为系统发送或者接收数据的时候,会锁用户内存的,比页面小的缓冲会浪费掉整个一个页面。(作为第一条的补充,建议把小包合并成大包发送)
KEY WORDS: UDP; IOCP; I/O; Completion Port
关键词: UDP; IOCP; I/O; 完成端口

 

### 回答1: IOCP(输入输出完成端口)是一种高效的异步通信模型,UDP是一种面向无连接的传输协议,C是一种编程语言。所以"IOCP UDP C demo"可以理解为使用IOCP和C语言实现UDP通信示例。 在这个示例中,我们可以使用C语言编写一个简单的程序,通过UDP协议进行数据的传输。首先,我们需要创建一个UDP套接字,通过该套接字与远程主机进行通信。接收方需要创建一个IOCP对象,并将套接字绑定在该IOCP对象上,以便异步地接收数据。 发送方可以使用sendto函数将数据发送给接收方。数据可以是任意类型的,例如文字、图片或者音频等。发送方只需要将数据写入套接字,并指定接收方的IP地址和端口号。 接收方在接收到数据时,会触发IOCP的回调函数,我们可以在回调函数中对数据进行处理。可以根据需要对数据进行解析或者存储等操作。 在整个过程中,IOCP实现了异步的数据传输,可以同时处理多个连接,提高了系统的性能。 总结来说,IOC UDP C demo是一个使用IOCP和C语言实现UDP通信示例程序,可以通过该示例了解IOCP的异步通信模型和C语言的编程技巧,以及UDP协议在网络通信中的应用。 ### 回答2: IOCP(Input/Output Completion Port)是一种高效的 I/O 处理机制,UDP(User Datagram Protocol)是一种无连接的传输协议,C 是一种编程语言,在下面的回答中,我将简要介绍 IOCp UDP C demo 的相关内容。 IOCp UDP C demo 是一个基于 IOCP 模型开发的 UDP 网络通信的示例程序,使用 C 语言编写。该示例程序主要用于展示如何使用 IOCP 来实现高性能的 UDP 网络通信。 在该示例程序中,首先会创建一个 IOCP 对象,并将其与一个 UDP 套接字绑定。然后,程序会创建多个工作者线程,每个线程都会调用 GetQueuedCompletionStatus 函数来等待 I/O 完成的通知。 当有 I/O 操作完成时,工作者线程会收到通知,并通过相关的数据结构获取完成的信息,比如接收到的数据、发送是否成功等。然后,线程根据具体的业务需求进行相应的处理,比如解析接收到的数据、发送响应等。 IOCP 可以实现高并发的网络通信,因为它使用了事件驱动的模型,可以同时处理多个 I/O 请求。而 UDP 是无连接的,没有连接的建立和断开的开销,适合实时性要求较高的应用场景,比如游戏中的实时通信。 通过这个示例程序,可以更好地了解 IOCP 模型的基本原理和使用方法,以及如何使用 UDP 进行高性能的网络通信。同时,可以根据自身需求进行改进和扩展,实现更复杂的网络应用。 总之,IOCp UDP C demo 是一个基于 IOCP 模型开发的 UDP 网络通信的示例程序,通过该示例程序可以学习和理解 IOCP 模型和 UDP 网络通信的相关知识。 ### 回答3: IOC(Input/Output Completion Ports)是一种高效的异步输入输出模型,UDP(User Datagram Protocol)是一种无连接的传输协议,而C Demo则指的是使用C语言编写的演示程序。 IOCUDP可以结合使用,通过IOC监听网络IO事件,实现高吞吐量的UDP数据传输。在C Demo中,我们可以使用Windows平台提供的IOCP机制,在C语言中编写代码来演示如何使用IOCUDP。 在C Demo中,首先需要创建一个套接字,用于监听和发送UDP数据包。然后,创建一个IOCP对象,用于管理套接字的异步IO操作。接下来,将套接字与IOCP对象关联起来,以便在IO事件发生时能够收到通知。 在程序运行时,我们可以使用多个线程来同时处理多个UDP连接。每个线程都会从IOCP对象中获取完成的IO事件,并根据不同的事件类型进行相应的处理。例如,当有数据包到达时,可以直接从套接字中读取数据并进行处理;当需要发送数据包时,可以将数据包写入套接字并发送。 通过使用IOCUDP,我们可以实现高效的网络数据传输,同时充分利用系统资源,提高程序的性能和响应速度。C Demo可以帮助我们理解和学习如何使用IOCUDP编写高性能的网络应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值