本文索引
总结经验
1)tcp传输包大小
报文大小:外网最大为1K,内网最大为30K
2)允许端口复用,否则使用使用过的端口需要等待一段时间
self.__sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
3)发送报文速度
发送报文速度上限与报文大小有一定关系,外网情况下1K的报文,移动端发送速度可以达到10个左右每秒,PC端可以达到50-100个左右
4) 接收方缓冲区大小需比报文大小大,最好大个5-10倍,否则容易出现缓冲区溢出问题
5)tcp协议是可靠传输协议,一般可以保证到达另一端以及到达顺序,但容易出现卡住的现象
代码实现
1)tcp.py TCP协议辅助类
#coding=UTF-8
import time
import threading
from socket import *
from md5 import *
from tmp import *
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
class TCPServer:
host=""
packet_size = 0
__Handler = None
__connect_count = 0
encrypt_handler = None
def __init__(self,host,port,connect_count,handler,packet_size,encrypt_handler=None,save_dir_path=""):
self.host = host
self.packet_size = packet_size
self.save_dir_path = save_dir_path
self.__connect_count = connect_count
self.__Handler = handler
self.encrypt_handler = encrypt_handler
address = (host,port)
self.__sock = socket(AF_INET,SOCK_STREAM)
self.__sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
self.__sock.bind(address)
self.__sock.listen(self.__connect_count)
print "[Server Online]"
whileƑ):
#接受一个新连接
session=self.__sock.accept()
#创建新线程来处理TCP连接
thread = threading.Thread(target=TCPServer.linkIn, args=(self,session,))
thread.start()
#新连接进入
def linkIn(self,session):
handler = self.__Handler(session,self.host,self.packet_size,self.encrypt_handler,self.save_dir_path)
handler.start()
class TCPClient:
__host=""
__packet_size = 0
__Handler = None
handler = None
sock = None
encrypt_handler = None
def __init__(self,remote_host,port,handler,packet_size,encrypt_handler=None,save_dir_path=""):
self.remote_host = remote_host
self.packet_size = packet_size
self.save_dir_path = save_dir_path
self.__Handler = handler
self.encrypt_handler = encrypt_handler
address = (remote_host,port)
self.sock = socket(AF_INET,SOCK_STREAM)
#连接服务器
self.sock.connect(address)
session = [self.sock,address]
#创建新线程读取数据
thread = threading.Thread(target=TCPClient.linkIn, args=(self,session,))
thread.start()
def linkIn(self,session):
self.handler = self.__Handler(session,self.remote_host,self.packet_size,self.encrypt_handler,self.save_dir_path)
self.handler.start()
class TCPHandler:
tcp = None
host=""
package_size=0
def __init__(self,session,host,package_size,encrypt_handler):
self.host = host
self.package_size = package_size
self.tcp = TCP(session,encrypt_handler)
def start(self):
#连接成功
self.onConnected()
#循环监听数据
while(self.tcp.isAlive()):
received_data = self.tcp.read()
if (received_data):
self.onReceivedData(received_data)
else:
time.sleep(0.001)
#print "onClose",self.tcp.isAlive
self.onClose()
#连接成功时
def onConnected(self):
pass
#接收到数据时
def onReceivedData(self,received_data):
pass
#处理接受数据
#发送数据
def sendData(self,data_key,data_value):
self.tcp.write(data_key,data_value)
#print "[send]",data_key,data_value
#关闭连接时
def onClose(self):
self.tcp.close()
self.top = None
#待修改
class TCP:
remote_addr = ""
__data_pool = ""
__data_list = []
__inside_data_list = []
__buffer=1024
__sock=None
__reader_thread = None
__encrypt_handler = None
__isAlive = None
def __init__(self,session,encrypt_handler):
self.__sock = session[0]
self.remote_addr = session[1]
#print "encrypt:",encrypt_handler
self.__encrypt_handler = encrypt_handler
self.__isAlive = True
#监听线程
self.__reader_thread = threading.Thread(target=TCP.readThread, args=(self,))
self.__reader_thread.start()
def isAlive(self):
return self.__isAlive
#设置缓冲区大小(单位字节)
def setBuffer(self,buffer):
self.__buffer = buffer
#处理内部协议
def __dealInsideProtocolData(self,data):
sender_addr = data["SenderAddr"]
key,value = data["Data"].split(":::",1)
#print "[receive]",key
if (key.find("FileSegment_")>=0):
#接收到文件数据包
key=key.split("FileSegment_",1)[1]
self.__inside_data_file_list.append({"SENDER_ADDR":sender_addr,"ID":key,"VALUE":value})
elif (key.find("receivedFileSegment")>=0):
#接收到接收反馈报文
value = int(value)
if (value in self.__wait_send_segment):
self.__wait_send_segment.remove(value)
#读取数据到数据列表
def readThread(self):
while(self.isAlive()):
try:
recv_data = self.__sock.recvfrom(self.__buffer)
except Exception:
#连接已断开
self.close()
break
self.__data_pool+=recv_data[0]
while (self.__data_pool.find(':::')>=0):
length,data = self.__data_pool.split(':::',1)
length = int(length)
if (len(data)>=length):
#数据完全
message_data = data[:length]
self.__data_pool = data[length:]
#解密报文
if (self.__encrypt_handler):
message_data = self.__encrypt_handler.decrypt(message_data)
if (message_data):
#确认报文有效
if (message_data.find(':::')>=0):
protocol,data = message_data.split(':::',1)
if (protocol=="CustomProtocol"):
#用户自定义报文
self.__data_list.append(data)
else:
#内部协议报文
self.__dealInsideProtocolData(data)
else:
#数据不完全,等待数据
break
#读取数据列表
def read(self):
if (self.__data_list):
return self.__data_list.popƐ)
else:
return None
#写数据
def __write(self,key,value,isInsideProtocol=False,send_to=None):
if (self.isAlive()):
if (isInsideProtocol):
key="InsideProtocol:::"+key
else:
key="CustomProtocol:::"+key
#print "[send]",key
data = key + ":::" + value
#加密报文
if (self.__encrypt_handler):
data = self.__encrypt_handler.encrypt(data)
data = str(len(data))+":::"+data
#分包发送数据
for segment in rangeƐ,len(data)/self.__buffer+1):
segment_data = data[segment*self.__buffer:(segment+1)*self.__buffer]
self.__sock.send(segment_data)
def write(self,key,value):
self.__write(key,value)
#关闭TCP通道
def close(self):
if (self.isAlive()):
print "[Tip]Diconnect!"
self.__isAlive = False
self.__sock.close()
self.__sock=None
2)md5.py MD5加密计算辅助函数库
#coding=utf-8 import hashlib import os #MD5辅助函数类 def MD5(value,isFile = False): if (isFile): return getFileMD5(value) else: return getStringMD5(value) #计算字符串的MD5码 def getStringMD5(string): myMd5 = hashlib.md5() myMd5.update(string) myMd5_Digest = myMd5.hexdigest() return myMd5_Digest #计算文件的MD5码 def getFileMD5(file_path): f = open(file_path,'rb') md5_obj = hashlib.md5() while True: d = f.read