引刀成一快

导航

 
这段时间看了不少网络程序的代码,也动手写了几个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()
    
        
需要说明的是:
1.Send可以显示的调用,但是recv则不行,你不能确定在什么时候能够收到,如果用轮询的方式,
        while RecvData():
                        sleep(100)
会把整个线程给"锁"住,除非你使用单独的线程来处理,比较合理的方法是使用non-blocking io,用select或者poll来管理socket句柄.当数据到来的时候,系统会发出通知.

2.在windows平台,如果你使用重叠IO,就不需要sendbuf,这样可以减少一次内存copy,
可以直接在栈里面定义一个buffer,扔给WSARecv,windows会替你管理这块内存.
------------------------------------------------------------------------------------------------------------
题外话:dudu能不能修改一下编辑器,支持wiki类似的语法,这样编辑,排版简单有效,现在这个不太好用,经常要去手工改html标签.
posted on 2005-12-25 16:13  tsbob  阅读(2765)  评论(5编辑  收藏  举报