本站首页    管理页面    写新日志    退出


«October 2025»
1234
567891011
12131415161718
19202122232425
262728293031


公告
 本博客在此声明所有文章均为转摘,只做资料收集使用。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:1304
评论数量:2242
留言数量:5
访问次数:7631021
建立时间:2006年5月29日




[Python]TCP网络程序的基本框架
软件技术

lhwork 发表于 2007/2/2 15:56:59

这段时间看了不少网络程序的代码,也动手写了几个server/client.总结一下,大部分网络程序使用的是tcp,用udp只有3个理由:1.允许一定的包丢失2.需要做nat穿透3.节省资源,如socket句柄. 而大多数应用层通讯协议,特别是数据量传输比较大的,为了效率和可靠性都会采用tcp.而TCP是流结构,应此要考虑2种情况:1.发送数据被阻塞2.接受包不完整或者多余.虽然tcp是stream,但是为了解析网络数据都是基于二进制封包或者基于文本的token形式存在. 对二进制的封包来说,一般结构如下: struct Pack {   char magic_num;   char pack_type;   int size;   char *data; }; 因为这样的结构,网络程序想要防止抓包,破解基本上很难.网游外挂光靠技术手段是没有什么用的.下面用python写了段伪码,无论是阻塞还是非阻塞,单线程还是多线程,基本上都应该采用如下的框架. class CSocket:     BUF_SIZE=(1024*16)      def __init__(self):         self.revbuf=[]          self.sedbuf=[]          self.handle=0           def handleError(self,e):         print e           def handleClose(self):         pass           def handleSend(self):         try:             send_bytes=self.handle.send(self.sedbuf)              self.sedbuf=self.sedbuf[send_bytes:]              #从buffer 中删除发送过的数据         except Exception,e:             self.handleError(e)          def handleRecv(self):         try:             data = self.handle.recv(BUF_SIZE)              if len(data)==0:                 self.handleClose()                  return              else:                 self.revbuf.append(data)              while self.revbuf:                 read_bytes,need_more = self.processPacket()                                   if need_more:                     break #当前buffer中的数据不是一个完整的数据包                 else:                     sef.revbuf=self.revbuf[read_bytes:]#从buffer中删掉解析过的数据                              except  Exception,e:             self.handleError(e)           def processPacket(self):         #解析封包,假设封包的魔法数是ox3a         if self.revbuf[0]!=0x3a:             return len(self.revbuf),True              #错误的数据,丢弃整个buffer         #advanced process.         pass               def Send(self,data):         self.sedbuf.append(data)          self.handleSend() 需要说明的是: Send可以显示的调用,但是recv则不行,你不能确定在什么时候能够收到,如果用轮询的方式,while RecvData():sleep(100)会把整个线程给”锁”住,除非你使用单独的线程来处理,比较合理的方法是使用non-blocking io,用select或者poll来管理socket句柄.当数据到来的时候,系统会发出通知. 在windows平台,如果你使用重叠IO,就不需要sendbuf,这样可以减少一次内存copy,可以直接在栈里面定义一个buffer,扔给WSARecv,windows会替你管理这块内存.


阅读全文(1925) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.742 second(s), page refreshed 144791124 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号