python TCP避免粘包的一种分装

总共两个组程序,
第一组为tcp服务端连接一个客户端
第二组为tcp服务端可连接多个客户端(通过线程进行了class分装)
python2,python3 均运行可用,具体解释见参考

避免粘包的核心代码,以下可运行例子,即将len_data 先通过一条tcp信号先发送过来,设置


            # while (len(buf) < len_data and recv_num < self.repeat_num):
            #     buftmp = client.recv(len_data - len(buf))
            #     buf = buf + buftmp
            #     recv_num = recv_num + 1
            #
            # if len(buf) != len_data:
            #     print("客户端应发送长度为" + str(len_data) + ", 实际接收长度为: " + str(len(buf)))
            #     print(buf)
            #     # time.sleep(100)
            #     print("跳过129")
            # else:
            #
            #     if str(buf) != "b''":
            #         if python_version == "2":
            #             original_return_data = buf.encode('hex')
            #         elif python_version == "3":
            #             original_return_data = buf.hex()
            #
            #         print("4444444444444444")
            #         print(len(buf))
            #
            #         print(str(client_addr) +"的地址原数据:"+ str(buf) +" ,转换成十六进制: " + str(original_return_data))
            #         ana2.distance_analysis(original_return_data)
            #     else:
            #         pass

一.只分装了服务端,但是只能连接接收一个客户端
server端

#!/usr/bin/env python2.7
#coding:utf-8
# -*- coding: utf-8 -*-

from socket import *
import json
import struct
import time
import threading

class Server_link():
    """用于初始化。tcp服务端"""
    def __init__(self,HOST = '127.0.0.1',PORT = 8081,listen_num = 3):
        self.HOST = HOST
        self.PORT = PORT
        self.listen_num = listen_num
        self.repeat_num = 10 #设置当没有接收到完整数据帧的时候,重复连接的次数
        self.try_num = 10 # 当客户端掉线后,尝试从连的次数,超过该次数没有连接成功,则认为客户端断线


    def start_server(self):
        """开启服务端"""

        self.server = socket(AF_INET, SOCK_STREAM)
        self.server.bind((self.HOST, self.PORT))
        self.server.listen(self.listen_num)
        t_server = threading.Thread(target=self.run)
        t_server.start()

    def run(self):
        """服务端监听程序"""
        while True:
            try_num = 0
            print('等待客户端连接......')  # 等待cilent的连接
            self.client, client_addr = self.server.accept()
            print("成功连接IP:" + str(client_addr) + "的客户端")  # (连接对象,客户端的ip和端口)
            print("\n")

            while True:
                 try:
                      length = self.client.recv(4)
                      len_data = struct.unpack('i', length)
                      len_data = len_data[0]
                      print('接收到的原始长度字符%s:' % length)
                      print('数据长度为%s:' % len_data)

                      buf = self.receive_real(len_data)
                      print("接收到的真实数据为: " + str(buf))

                      json_buf = json.loads(buf)
                      print(type(json_buf))
                      status = json_buf['status']
                      # self.logic_send(status)
                 except:
                      if try_num > self.try_num:
                           print(str(client_addr) + "的客户端连接中断!!!!")
                           break
                      else:
                           try_num = try_num + 1

    def receive_real(self,len_data):
        """接收真实数据"""
        """ len_data 为预先发过来的真实数据长度 """
        buf = b''
        recv_size = 0
        recv_num = 0  # 接收次数

        buf = self.client.recv(len_data)

        while (len(buf) <len_data and recv_num < self.repeat_num ):
            buftmp = self.client.recv(len_data - len(buf))
            buf = buf + buftmp
            recv_num = recv_num + 1

        if len(buf) != len_data:
            print("客户端应发送长度为" + str(len_data) +", 实际接收长度为: " + str(len(buf))  )
            time.sleep(100)

        return buf




if __name__ == '__main__':
    s = Server_link()
    s.start_server()
    print("开启tcp服务端线程拉起完成")

client 端

#!/usr/bin/env python2.7
#coding:utf-8
# -*- coding: utf-8 -*-


from socket import *
import json
import struct
import time
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8081))

while True:
#打开发1
     data={"status":"Link_m","dict": None}
     data=json.dumps(data)

     # data = "Head" + data
     length = len(data)

     len_data = struct.pack('i', length)
#固定字节长度,告知数据长度为多少
     client.send(len_data)
     client.send(data.encode('utf-8'))

server端输出:

接收到的真实数据为: {"status": "Link_m", "dict": null}
<type 'dict'>
接收到的原始长度字符"   :
数据长度为34:
接收到的真实数据为: {"status": "Link_m", "dict": null}
<type 'dict'>
接收到的原始长度字符"   :
数据长度为34:
接收到的真实数据为: {"status": "Link_m", "dict": null}
<type 'dict'>
接收到的原始长度字符"   :
数据长度为34:
接收到的真实数据为: {"status": "Link_m", "dict": null}

二.对服务端和客户端都加上了接收和发送的分装线程类的,一个服务端可以对应多个客户端

server端

#!/usr/bin/env python2.7
#coding:utf-8
# -*- coding: utf-8 -*-

from socket import *
import json
import struct
import time
import threading

class Server_link():
    """用于初始化。tcp服务端"""
    def __init__(self,HOST = '127.0.0.1',PORT = 8081,listen_num = 3):
        self.HOST = HOST
        self.PORT = PORT
        self.listen_num = listen_num
        self.repeat_num = 10 #设置当没有接收到完整数据帧的时候,重复连接的次数
        self.try_num = 10 # 当客户端掉线后,尝试从连的次数,超过该次数没有连接成功,则认为客户端断线
        self.client_addr_list = [] # 用于存储连接上的客户端的地址 # client_addr  来自 new_client_socket, client_addr = socket_tcp_server.accept()


    def start_server(self):
        """开启服务端"""

        self.server = socket(AF_INET, SOCK_STREAM)
        self.server.bind((self.HOST, self.PORT))
        self.server.listen(self.listen_num)
        t_server = threading.Thread(target=self.listen_client)
        t_server.start()

    def listen_client(self):
        """客户端监听程序,用于监听客户端的连接"""
        while True:

            print('等待客户端连接......')  # 等待cilent的连接
            self.hint_client_infor()
            client, client_addr = self.server.accept()
            self.link_client(client, client_addr) #成功获得客户端,开启针对于该客户端对应的接收与发送函数

    def hint_client_infor(self,symbol = ""):
        print("当前客户端连接数量: " + str(len(self.client_addr_list)))
        for i in self.client_addr_list:
            print(symbol + str(i))
        print("*" * 100)
        print("\n")

    def link_client(self,client,client_addr):

        self.client_addr_list.append((client,client_addr))
        # t_client_recv = threading.Thread(target=self.client_recv, args=((client,client_addr),))
        # t_client_recv.start()
        t_client_send = threading.Thread(target=self.client_send, args=((client,client_addr),))
        t_client_send.start()
        print("成功连接IP:" + str(client_addr) + "的客户端")  # (连接对象,客户端的ip和端口)
        print("\n")



    def client_recv(self,data):
        client = data[0]
        client_addr = data[1]
        try_num = 0
        while True:
            try:
                length = client.recv(4)
                len_data = struct.unpack('i', length)
                len_data = len_data[0]
                print('接收到的原始长度字符%s:' % length)
                print('数据长度为%s:' % len_data)

                buf = self.receive_real(client,len_data)
                print("接收到的真实数据为: " + str(buf))

                json_buf = json.loads(buf)
                print(type(json_buf))
                status = json_buf['status']

            except:
                if try_num > self.try_num:
                    print(str(client_addr) + "的客户端连接中断!!!!")
                    if data in self.client_addr_list:
                        self.client_addr_list.remove(data)
                    client.close()
                    self.hint_client_infor(symbol="recv: ")

                    break
                else:
                    try_num = try_num + 1

    def client_send(self,data):
        client = data[0]
        client_addr = data[1]
        try_num = 0
        json_data = {"status": "from_server", "dict": None}
        while True:
            try:
                self.send_data(client,json_data)
            except:
                if try_num > self.try_num:
                    print(str(client_addr) + "的客户端连接中断!!!!")
                    if data in self.client_addr_list:
                        self.client_addr_list.remove(data)
                    client.close()
                    self.hint_client_infor(symbol="send: ")
                    break
                else:
                    try_num = try_num + 1



    def receive_real(self,client,len_data):
        """接收真实数据"""
        """ len_data 为预先发过来的真实数据长度 """
        buf = b''
        recv_size = 0
        recv_num = 0  # 接收次数

        buf = client.recv(len_data)

        while (len(buf) <len_data and recv_num < self.repeat_num ):
            buftmp = client.recv(len_data - len(buf))
            buf = buf + buftmp
            recv_num = recv_num + 1

        if len(buf) != len_data:
            print("客户端应发送长度为" + str(len_data) +", 实际接收长度为: " + str(len(buf))  )
            time.sleep(100)

        return buf

    def send_data(self,client,json_data):
          """用于发送数据"""
          json_data = json.dumps(json_data)

          # data = "Head" + data
          length = len(json_data)

          len_data = struct.pack('i', length)
          # 固定字节长度,告知数据长度为多少
          client.send(len_data)
          client.send(json_data.encode('utf-8'))



if __name__ == '__main__':
    s = Server_link()
    s.start_server()
    print("开启tcp服务端线程拉起完成")

client端

#!/usr/bin/env python2.7
#coding:utf-8
# -*- coding: utf-8 -*-

from socket import *
import json
import struct
import time
import threading

class Client_link():
    """用于初始化。tcp客户端"""
    def __init__(self,HOST = '127.0.0.1',PORT = 8081):
        self.HOST = HOST
        self.PORT = PORT
        self.repeat_num = 10 #设置当没有接收到完整数据帧的时候,重复连接的次数


    def start_client(self):
        """开启客户端"""

        self.client = socket(AF_INET, SOCK_STREAM)
        self.client.connect((self.HOST, self.PORT))
        t_client = threading.Thread(target=self.run)
        t_client.start()

    def run(self):
        """客户端监听程序"""
        while True:
            print('开始连接下位机服务端......')  # 等待cilent的连接
            while True:
                length = self.client.recv(4)
                len_data = struct.unpack('i', length)
                len_data = len_data[0]
                print('接收到的原始长度字符%s:' % length)
                print('数据长度为%s:' % len_data)

                buf = self.receive_real(len_data)
                print("接收到的真实数据为: " + str(buf))

                json_buf = json.loads(buf)
                print(type(json_buf))
                status = json_buf['status']
                #self.logic_send(status)



    def receive_real(self,len_data):
        """接收真实数据"""
        """ len_data 为预先发过来的真实数据长度 """
        buf = b''
        recv_size = 0
        recv_num = 0  # 接收次数

        buf = self.client.recv(len_data)

        while (len(buf) <len_data and recv_num < self.repeat_num ):
            buftmp = self.client.recv(len_data - len(buf))
            buf = buf + buftmp
            recv_num = recv_num + 1

        if len(buf) != len_data:
            print("服务端应发送长度为" + str(len_data) +", 实际接收长度为: " + str(len(buf))  )
            time.sleep(100)

        return buf

    def send_data(self,data):
          """用于发送数据"""

          data = json.dumps(data)

          # data = "Head" + data
          length = len(data)

          len_data = struct.pack('i', length)
          # 固定字节长度,告知数据长度为多少
          self.client.send(len_data)
          self.client.send(data.encode('utf-8'))





if __name__ == '__main__':
    c = Client_link()
    c.start_client()
    print("开启tcp客户端线程拉起完成")

    # data = {"status": "cscs", "dict": None}
    # while True:
    #      c.send_data(data)
    #      time.sleep(0.5)

服务端连接输出

等待客户端连接......开启tcp服务端线程拉起完成

当前客户端连接数量: 0
****************************************************************************************************


成功连接IP:('127.0.0.1', 55969)的客户端


等待客户端连接......
当前客户端连接数量: 1
(<socket.socket fd=716, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8081), raddr=('127.0.0.1', 55969)>, ('127.0.0.1', 55969))
****************************************************************************************************


('127.0.0.1', 55969)的客户端连接中断!!!!
当前客户端连接数量: 0
****************************************************************************************************


成功连接IP:('127.0.0.1', 55971)的客户端


等待客户端连接......
当前客户端连接数量: 1
(<socket.socket fd=724, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8081), raddr=('127.0.0.1', 55971)>, ('127.0.0.1', 55971))
****************************************************************************************************


成功连接IP:('127.0.0.1', 55972)的客户端


等待客户端连接......
当前客户端连接数量: 2
(<socket.socket fd=724, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8081), raddr=('127.0.0.1', 55971)>, ('127.0.0.1', 55971))
(<socket.socket fd=808, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8081), raddr=('127.0.0.1', 55972)>, ('127.0.0.1', 55972))
****************************************************************************************************



客户端连接输出

数据长度为39:
接收到的真实数据为: {"status": "from_server", "dict": null}
<type 'dict'>
接收到的原始长度字符'   :
数据长度为39:
接收到的真实数据为: {"status": "from_server", "dict": null}
<type 'dict'>
接收到的原始长度字符'   :
数据长度为39:
接收到的真实数据为: {"status": "from_server", "dict": null}
<type 'dict'>
接收到的原始长度字符'   :
数据长度为39:
接收到的真实数据为: {"status": "from_server", "dict": null}
<type 'dict'>
接收到的原始长度字符'   :
数据长度为39:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员进化不脱发!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值