• 网络编程(day2)


    网络编程中的服务,客户端与服务端交互命令的时候,有一种现像是粘包,(接收1024个数据)而发送的太多,一次收不完,会收几次,造成信息不正确

    粘包:根本原因是TCP协议是一种面向流的协议,

      在客户端粘包,服务端一次发送过多的信息(如cat /etc/passwd),你客户端只接受1024个字符

      在服务端粘包,连续两次发送比较短的数据,因为cpu的速度过快,所以,在缓存中直接连在一起,(因为比网络IO快)

    就造成了粘包现像

    http://www.cnblogs.com/linhaifeng/articles/6129246.html

    subprocess模块    struct模块 参考

    struct.pack包,
    报头
      一定要固定长度
      包含对将要发送数据的描述信息


    socket套接字只能发送bytes格式
    编码只能对字符不能编数字所以就有了,struct模块是把数字转成固定长度的bytes

    json struct模块解决粘包现像

    步骤:

    1,定义报头字典

    2,json序列化然后,编码成二进制,计算字典的长度(数据的长度在字典中)

    3,sturct发送固定长度,把数据字典的长度的发送,再发送数据

    4,客户端sturct先收固定的i ,4个字节 ,,得到字典的长度,连续收完字典长度

    5,反序列化,解码,然后得到字典,再得到字典中数据长度,开始收数据,

     

    ########################################

    粘包现像代码实例
    
    服务端
    
    #买手机
    import socket,time
    import subprocess
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #绑定电话卡
    ip_port=('127.0.0.1',8080)
    phone.bind(ip_port)
    phone.listen(5)
    conn,addr=phone.accept()
    
    
    # data1=conn.recv(1024)
    # data2=conn.recv(1024)
    
    data1=conn.recv(1) #b'h'
    
    time.sleep(5)
    data2=conn.recv(1024) #b'elloworldSB'
    
    #
    print('第一个包',data1)
    print('第二个包',data2)
    
    
    
    
    
    
    
    
    
    客户端
    
    #买手机
    import socket,time
    import subprocess
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #绑定电话卡
    ip_port=('127.0.0.1',8080)
    phone.connect(ip_port)
    
    #
    phone.send('helloworld'.encode('utf-8'))
    time.sleep(3)
    phone.send('SB'.encode('utf-8'))

    ######################################################

     #####################################################

    json,struct,  解决粘包问题的服务端与客户端代码(执行显示比较大的命令)

    服务端

    #coding:utf-8
    #买手机
    import socket
    import struct
    import json
    import subprocess
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #绑定电话卡
    ip_port=('192.168.16.114',8081)
    phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    phone.bind(ip_port)
    #开机
    phone.listen(5)
    #等待电话
    
    #链接循环
    while True:
        conn,addr=phone.accept()
        print('client addr',addr)
        #通讯循环
        while True:
            try:
                cmd=conn.recv(1024)
                res=subprocess.Popen(cmd.decode('utf-8'),
                                 shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
                out_res=res.stdout.read()
                err_res=res.stderr.read()
                data_size=len(out_res)+len(err_res)
                head_dic={'data_size':data_size}
                head_json=json.dumps(head_dic)
                head_bytes=head_json.encode('utf-8')
    
                #part1:先发报头的长度
                head_len=len(head_bytes)
                conn.send(struct.pack('i',head_len))
                #part2:再发送报头
                conn.send(head_bytes)
                #part3:最后发送数据部分
                conn.send(out_res)
                conn.send(err_res)
    
            except Exception:
                break
    
        conn.close()
    phone.close()

    客户端

    # 买手机
    import socket
    import struct
    import json
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 拨通电话
    # ip_port = ('127.0.0.1', 8080)
    ip_port = ('192.168.16.114', 8081)
    phone.connect(ip_port)
    # 通信循环
    while True:
        # 发消息
        cmd = input('>>: ').strip()
        if not cmd: continue
        phone.send(bytes(cmd, encoding='utf-8'))
    
        # part1:先收报头的长度
        head_struct=phone.recv(4)
        head_len=struct.unpack('i',head_struct)[0]
    
        # part2:再收报头
        head_bytes=phone.recv(head_len)
        head_json=head_bytes.decode('utf-8')
    
        head_dic=json.loads(head_json)
        print(head_dic)
        data_size = head_dic['data_size']
    
        #part3:收数据
        recv_size = 0
        recv_data = b''
        while recv_size < data_size:
            data = phone.recv(1024)
            recv_size += len(data)
            recv_data += data
    
        print(recv_data.decode('utf-8'))
    phone.close()

    #######################################################

    #######################################################

    ftp上传下载文件代码实例 

    服务端

    import socket
    import struct
    import json
    import subprocess
    import os
    
    class MYTCPServer:
        address_family = socket.AF_INET
    
        socket_type = socket.SOCK_STREAM
    
        allow_reuse_address = False
    
        max_packet_size = 8192
    
        coding='utf-8'
    
        request_queue_size = 5
    
        server_dir='file_upload'
    
        def __init__(self, server_address, bind_and_activate=True):
            """Constructor.  May be extended, do not override."""
            self.server_address=server_address
            self.socket = socket.socket(self.address_family,
                                        self.socket_type)
            if bind_and_activate:
                try:
                    self.server_bind()
                    self.server_activate()
                except:
                    self.server_close()
                    raise
    
        def server_bind(self):
            """Called by constructor to bind the socket.
            """
            if self.allow_reuse_address:
                self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.socket.bind(self.server_address)
            self.server_address = self.socket.getsockname()
    
        def server_activate(self):
            """Called by constructor to activate the server.
            """
            self.socket.listen(self.request_queue_size)
    
        def server_close(self):
            """Called to clean-up the server.
            """
            self.socket.close()
    
        def get_request(self):
            """Get the request and client address from the socket.
            """
            return self.socket.accept()
    
        def close_request(self, request):
            """Called to clean up an individual request."""
            request.close()
    
        def run(self):
            while True:
                self.conn,self.client_addr=self.get_request()
                print('from client ',self.client_addr)
                while True:
                    try:
                        head_struct = self.conn.recv(4)
                        if not head_struct:break
    
                        head_len = struct.unpack('i', head_struct)[0]
                        head_json = self.conn.recv(head_len).decode(self.coding)
                        head_dic = json.loads(head_json)
    
                        print(head_dic)
                        #head_dic={'cmd':'put','filename':'a.txt','filesize':123123}
                        cmd=head_dic['cmd']
                        if hasattr(self,cmd):
                            func=getattr(self,cmd)
                            func(head_dic)
                    except Exception:
                        break
    
        def put(self,args):
            file_path=os.path.normpath(os.path.join(
                self.server_dir,
                args['filename']
            ))
    
            filesize=args['filesize']
            recv_size=0
            print('----->',file_path)
            with open(file_path,'wb') as f:
                while recv_size < filesize:
                    recv_data=self.conn.recv(self.max_packet_size)
                    f.write(recv_data)
                    recv_size+=len(recv_data)
                    print('recvsize:%s filesize:%s' %(recv_size,filesize))
    
    
    tcpserver1=MYTCPServer(('127.0.0.1',8080))
    
    tcpserver1.run()
    
    
    
    
    
    
    

    客户端

    import socket
    import struct
    import json
    import os
    
    
    
    class MYTCPClient:
        address_family = socket.AF_INET
    
        socket_type = socket.SOCK_STREAM
    
        allow_reuse_address = False
    
        max_packet_size = 8192
    
        coding='utf-8'
    
        request_queue_size = 5
    
        def __init__(self, server_address, connect=True):
            self.server_address=server_address
            self.socket = socket.socket(self.address_family,
                                        self.socket_type)
            if connect:
                try:
                    self.client_connect()
                except:
                    self.client_close()
                    raise
    
        def client_connect(self):
            self.socket.connect(self.server_address)
    
        def client_close(self):
            self.socket.close()
    
        def run(self):
            while True:
                inp=input(">>: ").strip()
                if not inp:continue
                l=inp.split()
                cmd=l[0]
                if hasattr(self,cmd):
                    func=getattr(self,cmd)
                    func(l)
    
    
        def put(self,args):
            cmd=args[0]
            filename=args[1]
            if not os.path.isfile(filename):
                print('file:%s is not exists' %filename)
                return
            else:
                filesize=os.path.getsize(filename)
    
            head_dic={'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize}
            print(head_dic)
            head_json=json.dumps(head_dic)
            head_json_bytes=bytes(head_json,encoding=self.coding)
    
            head_struct=struct.pack('i',len(head_json_bytes))
            self.socket.send(head_struct)
            self.socket.send(head_json_bytes)
            send_size=0
            with open(filename,'rb') as f:
                for line in f:
                    self.socket.send(line)
                    send_size+=len(line)
                    print(send_size)
                else:
                    print('upload successful')
    
    
    
    
    client=MYTCPClient(('192.168.16.114',8080))
    
    client.run()
  • 相关阅读:
    Angular 项目打包之后,部署到服务器,刷新访问404解决方法
    C# yield return; yield break;
    C#获取枚举描述
    21、uwp UI自动化测试(WinAppDriver)
    20、uwp打包失败(All app package manifests in a bundle must declare the same values under the XPath *[local-name()='Package']/*[local-name()='Dependencies'])
    19、UWP 新特性(Creator Update)
    18、利用 Windows Device Portal 获取用户闪退 dump
    17、uwp 打包失败记录
    爱奇艺招聘uwp开发
    16、C++获取磁盘空间的方法
  • 原文地址:https://www.cnblogs.com/wanchenxi/p/7734954.html
Copyright © 2020-2023  润新知