iocp的python封装(示例)

发布时间:2019-10-16编辑:脚本学堂
介绍下python实现iocq封装的方法,学习下python使用pyiocp实现iocq封装的原理与应用,有需要的朋友参考下。

有关IOCP的资料在网上有很多,本文只分享一下pyiocp的实现原理。
第一次封装时,用一张图来描述使用pyiocp收发数据的过程:
python封装iocq

由上图可以看出,服务器接收、发送的数据都通过pyiocp。

在实际使用过程中,发现这种实现模式有一个问题:游戏服务器发送的数据包,一般都比较小(最大的也不过几K),而每个socket的低层协议栈缓冲区大小默认是32K,除非出
现下面两种情况会使缓冲区填满而收到相应的socket错误,一是在极短的时间内发送的数据量超过32K,二是客户端的网络极差,放在缓冲区里的数据半天也没发出去。

第一种情况,在游戏服务器中是不会出现的,而对于第二种情况,如果不及时的关闭这种连接,那么发送给这个连接的数据将不断的堆积在内存里,使内存占用越来越大。所
以,我觉得没有必要通过pyiocp发送数据,这样增加了程序的复杂性的同时,也没带来多少好处。

索性直接通过socket发送,如果发送时收到socket错误(在send时很少会发生错误,即使出错,缓冲区满是主要原因),就把该连接断掉。

所以,新设计之后的pyiocp内部工作模式是这样的:
pyiocq工作模式
除了以上所讲的实现模式不一样之后,新封装的pyiocp使用了内存池。
内存池是一年前写的,实现参考了python源码的内存池实现。

pyiocp模块的使用

pyiocp模块提供的方法:
init(): 初始化内部使用的资源。在调用其他函数之前,必须先调用该方法。
如果调用成功,返回0,否则,返回一个错误码,可以通过errinfo(errno)来查看错误码的描述。一般在程序启动的时候调用该方法。
cleanup(): 释放内部使用的资源。
run(ip, port): 启动pyiocp监听。参数ip为字符串,表示绑定的本地IP地址,参数port是一个整数,表示监听的端口。
函数调用成功,返回0,否则返回一个错误码。
stop(): 停止监听。调用该方法后,原先在事件队列中未处理的事件将被清空。
send(fileno, data): 发送数据。参数fileno表示socket句柄,data为发送的数据。上面讲到数据是直接发送给客户端的,那么与这里讲的岂不矛盾。其实,send内部实现只
是简单地调用winsocket的send()方法,而没用使用WSASend投递。所以并不矛盾。函数返回0表示数据发送成功,否则应该通过errinfo(errno)来查看错误信息。
close(fileno):关闭连接。参数fileno表示将要关闭的socket句柄。函数返回0表示操作成功,否则应该通过errinfo(errno)来查看错误信息。
event():获取一个事件。如果队列中没有事件,返回None。事件是一个包含三个元素的元组,[0]表示事件的类型,0: NET_NEW,1: NET_LEAVE,2: DATA_NEW。[1]表示对应
的socket句柄。[2]表示相应的数据,NET_NEW事件的数据是ip,port,NET_LEAVE事件的数据为None,DATA_NEW事件的数据为二进制字符串。
count(): 返回当前连接的数量。
errinfo(errno): 查看错误码对应的信息。

代码:
 

复制代码 代码示例:
#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
# edit: www.jb200.com
#
import pyiocp 
import time 
 
NET_NEW = 0 
NET_LEAVE = 1 
DATA_NEW = 2 
 
pyiocp.init() 
pyiocp.run('127.0.0.1', 1234) 
while True: 
    event = pyiocp.event() 
    if event is None: 
        time.sleep(0.1) 
        continue 
     
    type, fileno, data = event 
    if type == NET_NEW: 
        ip = data 
        print '---->', ip 
    elif type == NET_LEAVE: 
        print '<----' 
    else: 
        print 'recv data:', data 
         
pyiocp.stop() 
pyiocp.cleanup() 

附,源码下载与编译
pyiocp_new(http://darkbull.net/static/upload/0/pyiocp_new.7z):使用gcc编译,在编译时修改makefile中的python版本

pyiocp_old(http://darkbull.net/static/upload/0/pyiocp_old.7z):使用c++编写,其中有vs与CodeBlocks的项目文件