多线程应用libevent练习---流程图
2016-11-23 22:11:23 64 举报
AI智能生成
这是一个linux下多线程应用Libevent的流程图。 其实从设计和效率上来说,这个多线程用法是不好的,应该使用单线程多进程的设计。 此代码纯为练习C用。
作者其他创作
大纲/内容
初始化
初始化recv收包缓存g_Buffer_Temp
初始化sockfd哈希表g_ConnBuffer_Table
初始化数据包缓存g_Queue
typedef struct BufferUnit{
int buffer_type;
void *ptr;
evutil_socket_t sockfd;
struct BufferUnit* prev;
struct BufferUnit* next;
}Buffer_Unit;
void *ptr
typedef struct Buffer_Read{
evutil_socket_t sockfd;
BUFF_READ_T *buffer;
}Buffer_Read;
typedef struct Buffer_Conn{
evutil_socket_t sockfd;
char ip_addr[IP_ADDR_LEN];
struct bufferevent *bev;
}Buffer_Conn;
初始化python线程设置
PyEval_InitThreads
PyThreadState* state=PyEval_SaveThread()
线程 RecvThread
evthread_use_pthreads
event_base_new
event_set_fatal_callback
致命错误回调函数OnFatalErr_CB
初始化 struct sockaddr_in fsin 设置端口和协议族
evconnlistener_new_bind
连接事件回调OnNewConnect_CB
bufferevent_socket_new创建bufferevent对象evobj
bufferevent_setcb设置回调函数
收到数据回调OnRead_CB
取得数据缓存指针struct evbuffer *input=bufferevent_get_input(evobj);
创建一个新的缓存对象 struct evbuffer *buffer=evbuffer_new();
让buffer支持锁 evbuffer_enable_locking(buffer,NULL);
把input指向的数据赋值给Buffer evbuffer_add_buffer(buffer,input);
创建一个读取缓存包并压入g_Queue
Buffer_Unit *unit=Create_Unit_Read( sockfd,buffer );
pthread_mutex_lock
Buffer_Add_Queue(g_Queue,unit);
pthread_mutex_unlock
发送数据回调OnWrite_CB
触发事件回调OnEvent_CB
closeconnect(sockfd)
bufferevent_enable(evobj,EV_READ|EV_WRITE|EV_PERSIST)设置事件为 读、写、持久
将socket描述符client压入哈希表g_ConnBuffer_Table
pthread_mutex_lock
Conn_Buffer_New(g_ConnBuffer_Table,client);
pthread_mutex_unlock
创建一个连接缓存包并压入g_Queue
Buffer_Unit *unit=Create_Unit_Conn( client,addr,evobj)
pthread_mutex_lock
Buffer_Add_Queue(g_Queue,unit)
pthread_mutex_unlock
evconnlistener_set_error_cb
连接失败回调OnAcceptError_CB
evsignal_new & event_add 设置中断事件的回调
触发信号回调OnSignal_INT_CB
event_base_dispatch 进入事件循环
结束循环,释放资源
线程 ScriptThread
获取Python全局解释器锁 PyGILState_STATE state = PyGILState_Ensure();
加载需要调用的Python模块和函数对象
创建局部变量 Buffer_Queue *queue_loop=Create_Queue
进入 while(1) 无限循环
将g_Queue当前的数据全部复制给queue_loop
pthread_mutex_lock
cnt_unit=Copy_Queue(queue_loop,g_Queue)
pthread_mutex_unlock
判断是否有数据赋值给 queue_loop
cnt_unit<=0
睡眠usleep(1000)
进入下一次循环continue
cnt_unit>0
unit=Buffer_Pop_Queue(queue_loop);
进入while(unit)循环
如果unit是连接缓存包
获取包指向的sockfd、evobj、ip_addr
0==strlen(ip_addr) 处理断线包
colseconnect_step2(sockfd,evobj)
调用Python函数DisConnect
0!=strlen(ip_addr) 处理新连接包
记录玩家sockfd并与evobj关联 record_sockfd_libevent
调用Python函数Login
释放unit资源 Free_Queue_Unit_Conn
如果unit是读取缓存包
获取包指向的sockfd、struct evbuffer * buffer
初始化收包缓存 g_Buffer_Temp
将数据流以BUFFSIZE为长度单位,将数据从buffer复制给g_Buffer_Temp,再压入解包队列
while( (readlen=evbuffer_remove(buffer,g_Buffer_Temp,BUFFSIZE))>0 )
setbuffer_unpack(sockfd,g_Buffer_Temp,readlen);
memset(g_Buffer_Temp,'\0',BUFFSIZE_EXT);
判断并试图进入解包逻辑 while( get_validunpack(sockfd) > 0 )
获取协议号 proto=getbuffer_unpack(sockfd)
调用Python函数OnCommand,由Python层操作协议
解包
UnPackInt
UnPackString
发送请求
PacketPrepare
PacketInt
PacketString
PacketSend
释放unit资源 Free_Queue_Unit_Read(unit);
循环末尾再把新的unit弹出来 unit=Buffer_Pop_Queue(queue_loop);
若开启了时间统计,统计时间并将结果作为参数调用Python函数 LoopStatistics_Libev
短暂睡眠usleep(100),然后重新进入while(1)循环
释放生成的Python模块和函数对象
释放python全局解释器锁 PyGILState_Release(state)
Thread_Wait等待两个线程结束
PyEval_AcquireLock()
PyThreadState_Swap(state)
进入断线阶段1
取消evobj的读写权限 bufferevent_disable(evobj,EV_READ|EV_WRITE)
创建一个连接缓存包并压入队列
Buffer_Unit *unit=Create_Unit_Conn( sockfd,"",evobj);
pthread_mutex_lock
Buffer_Add_Queue(g_Queue,unit)
pthread_mutex_unlock
进入断线阶段2
把sockfd从解包队列移除 remove_sockfd(sockfd)
释放evobj对象 bufferevent_free(evobj)
pthread_mutex_lock
把sockfd从g_ConnBuffer_Table中移除 Conn_Buffer_Free(g_ConnBuffer_Table,sockfd)
pthread_mutex_unlock
0 条评论
下一页