Python TCP传输协议总结

本文索引

总结经验



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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值