• day30——socket套接字(完全版)


    day30

    基于TCP协议的socket循环通信

    server
    import socket
    phone = socket.socket()
    phone.bind(("127.0.0.1", 8080))
    phone.listen()
    conn, addr = phone.accept()
    
    from_client_data = conn.recv(1024)
    print(f"来自客户端的消息:{from_client_data.decode('utf-8')}")
    
    conn.close()
    phone.close()
    
    client
    import socket
    phone = socket.socket()
    phone.connect(("127.0.0.1", 8080))
    data = input("请输入>>>")
    phone.send(data.encode("utf-8"))
    phone.close()
    

    基于TCP协议的socket 链接+循环 通信

    代码功能:服务器不会断开,客户端可以断开(且不能输入空字符串)

    server
    import socket
    phone = socket.socket()
    phone.bind(("127.0.0.1", 8080))
    phone.listen(3)
    while 1:
        conn, addr = phone.accept()
        print(f"{addr}客户端连接了")
        while 1:
            try:
                from_client_data = conn.recv(1024)
                if from_client_data.decode("utf-8").upper() == "Q":
                    print(f"{addr}客户端通信关闭!")
                    break
                else:
                    print(f"来自客户端的消息:{from_client_data.decode('utf-8')}")
                while True:
                    data = input("请输入>>>")
                    if not data:
                        print("输入内容不为空!")
                        continue
                    else:
                        break
                conn.send(data.encode("utf-8").upper())
            except Exception:
                print(f"{addr}客户端通信关闭!")
                break
        conn.close()
    phone.close()
    
    clicent
    import socket
    phone = socket.socket()
    phone.connect(("127.0.0.1", 8080))
    while 1:
        try:
            data = input("请输入>>>")
            if not data:
                print("输入内容不为空!")
                continue
            phone.send(data.encode("utf-8"))
            if data.upper() == "Q":
                print("通信关闭!")
                break
    
            from_server_data = phone.recv(1024)
            if from_server_data.decode("utf-8").upper() == "Q":
                print("通信关闭!")
                break
            else:
                print(f"来自服务器的消息:{from_server_data.decode('utf-8')}")
        except Exception:
            print("通信关闭!")
            break
    phone.close()
    

    基于TCP协议的socket通信:实例:远程执行命令

    bates:网络传输,文件存储时

    server
    import socket
    phone = socket.socket()
    phone.bind(("127.0.0.1", 8080))
    phone.listen(3)
    while 1:
        conn, addr = phone.accept()
        print(f"{addr}客户端连接了")
        while 1:
            try:
                from_client_data = conn.recv(1024)
                import subprocess
                obj = subprocess.Popen(from_client_data.decode('utf-8'),
                                       shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE,
                                       )
                conn.send((obj.stdout.read() + obj.stderr.read()).upper())
            except Exception:
                print(f"{addr}客户端通信关闭!")
                break
        conn.close()
    phone.close()
    
    client
    import socket
    phone = socket.socket()
    phone.connect(("127.0.0.1", 8080))
    while 1:
        try:
            data = input("请输入>>>")
            if not data:
                print("输入内容不为空!")
                continue
            phone.send(data.encode("utf-8"))
            if data.upper() == "Q":
                print("通信关闭!")
                break
    
            from_server_data = phone.recv(1024)
            print(from_server_data.decode('gbk'))
        except Exception:
            print("通信关闭!")
            break
    phone.close()
    

    粘包现象

    为什么出现粘包?

    只有TCP有粘包现象,UDP永远不会粘包!

    操作系统的缓冲区

    • 为什么存在缓冲区
      • 暂时存储一些数据
      • 缓冲区存在如果你的网络波动,保证数据的收发稳定,匀速

    缺点:造成了粘包现象之一

    什么情况下出现粘包?

    • 出现粘包的情况

      • 客户端发送了一段数据过大,服务端只收了一部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包

      server

      # import socket
      # import subprocess
      # phone = socket.socket()
      # phone.bind(('127.0.0.1',8848))
      # phone.listen(2)
      # # listen: 2 允许有两个客户端加到半链接池,超过两个则会报错
      
      # while 1:
      #     conn,addr = phone.accept()  # 等待客户端链接我,阻塞状态中
      #     # print(f'链接来了: {conn,addr}')
      #     while 1:
      #         try:
      #             from_client_data = conn.recv(1024)  # 最多接受1024字节
      #             if from_client_data.upper() == b'Q':
      #                 print('客户端正常退出聊天了')
      #                 break
      #             obj = subprocess.Popen(from_client_data.decode('utf-8'),
      #                                    shell=True,
      #                                    stdout=subprocess.PIPE,
      #                                    stderr=subprocess.PIPE,
      #                                    )
      #             result = obj.stdout.read() + obj.stderr.read()
      #             print(f'总字节数:{len(result)}')
      #             conn.send(result)
      #         except ConnectionResetError:
      #             print('客户端链接中断了')
      #             break
      #     conn.close()
      # phone.close()
      

      client

      # import socket
      #
      # phone = socket.socket()
      #
      # phone.connect(('127.0.0.1',8848))
      # while 1:
      
      # to_server_data = input('>>>输入q或者Q退出').strip().encode('utf-8')
      
      # if not to_server_data:
      
      # # 服务端如果接受到了空的内容,服务端就会一直阻塞中,所以无论哪一端发送内容时,都不能为空发送
      
      # print('发送内容不能为空')
      
      # continue
      
      # phone.send(to_server_data)
      
      # if to_server_data.upper() == b'Q':
      
      # break
      
      # from_server_data = phone.recv(300)  # 最多接受1024字节
      
      # # print(f'{from_server_data.decode("gbk")}')
      
      # print(len(from_server_data))
      
      # phone.close()
      
      • 连续短暂的send多次(数据量很小),你的数据会统一发送出去

    server

    2. 连续短暂的send多次(数据量很小),你的数据会统一发送出去.
    # import socket
    
    
    # phone = socket.socket()
    
    #
    
    # phone.bind(('127.0.0.1',8848))
    
    #
    
    # phone.listen(5)
    
    #
    #
    
    # conn,addr = phone.accept()  # 等待客户端链接我,阻塞状态中
    
    #
    
    # from_client_data = conn.recv(1024)  # 最多接受1024字节
    
    # print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
    
    # conn.close()
    
    # phone.close()```python
    

    client

      ```python
      # 2. 连续短暂的send多次(数据量很小),你的数据会统一发送出去.
      
      # import socket
      #
      # phone = socket.socket()
    #
      # phone.connect(('127.0.0.1',8848))
    #
      #
      # phone.send(b'he')
      # phone.send(b'll')
      # phone.send(b'o')
      #
      #
      # phone.close()
      # Nigle算法
    

    深入研究收发

    不一定是一收一发

    • 发多次收一次

    server

    # 发多次收一次
    # import socket
    # phone = socket.socket()
    # phone.bind(('127.0.0.1',8848))
    # phone.listen(5)
    
    # conn,addr = phone.accept()  # 等待客户端链接我,阻塞状态中
    # from_client_data = conn.recv(1024)  # 最多接受1024字节
    # print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
    
    # conn.close()
    # phone.close()
    

    client

    # 发多次收一次
    import socket
    phone = socket.socket()
    phone.connect(('127.0.0.1',8848))
    
    phone.send(b'he')
    phone.send(b'llo')
    phone.close()
    Nigle算法
    
    • 发一次收多次

    server

    # 发一次收多次
    # import socket
    # phone = socket.socket()
    # phone.bind(('127.0.0.1',8848))
    # phone.listen(5)
    
    # conn,addr = phone.accept()  # 等待客户端链接我,阻塞状态中
    # from_client_data = conn.recv(3)  # 最多接受1024字节
    # print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
    # from_client_data = conn.recv(3)  # 最多接受1024字节
    # print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
    # from_client_data = conn.recv(3)  # 最多接受1024字节
    # print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
    # from_client_data = conn.recv(3)  # 最多接受1024字节
    # print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
    
    # conn.close()
    # phone.close()
    

    client

    # 发一次收多次
    # import socket
    # phone = socket.socket()
    # phone.connect(('127.0.0.1',8848))
    # phone.send(b'hello world')
    # phone.close()
    

    如何解决粘包现象

    解决粘包现象的思路:

    服务端发一次数据 10000字节

    客户端接收数据时,循环接收,每次(至多)接收1024个字节,直至将所有的字节全部接收完毕,将接收的数据拼接在一起,最后解码

    • 遇到的问题1:recv的次数无法确定

      你发送总具体数据之前,先给我发一个总数据长度:5000个字节,如何在发送总数居

      客户端:先接收一个长度,5000个字节

      然后我再循环recv 控制循环的条件就是只要你接收的数据< 5000 一直接收

    • 遇到的问题2:总数据的长度转化成的字节数不固定

    你要将total_size int类型转化成bytes类型才可以发送

    387 ---- > str(387) '387' ---->bytes b'387' 长度 3bytes

    4185 ----> str(4185) '4185' ---->bytes b'4185' 长度 4bytes

    18000------------------------------------------------------> 长度 5bytes

    我们要解决:

    将不固定长度的int类型转化成固定长度的bytes并且还可以翻转回来

    struct模块

    服务端:
    import struct
    total_size = len(result)
    print(f'总字节数:{total_size}')
    head_bytes = struct.pack('i',total_size)
    conn.send(head_bytes)
    
    conn.send(result)
    total_size int类型
    
    客户端:
    head_bytes = phone.recv(4)
    total_size = struct.unpack('i',head_bytes)[0]
    

    low版解决粘包现象

    server
    import socket
    import subprocess
    import struct
    phone = socket.socket()
    phone.bind(("127.0.0.1", 8080))
    phone.listen(3)
    while 1:
        conn, addr = phone.accept()
        print(f"{addr}客户端连接了")
        while 1:
            try:
                from_client_data = conn.recv(1024)
                obj = subprocess.Popen(from_client_data.decode('utf-8'),
                                       shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE,
                                       )
                data = obj.stdout.read() + obj.stderr.read()
                data_len = len(data)
                print(f"长度:{len(data)}")
                conn.send(struct.pack("i", data_len))
                conn.send(data)
            except Exception:
                print(f"{addr}客户端通信关闭!")
                break
        conn.close()
    phone.close()
    
    client
    import socket
    import struct
    phone = socket.socket()
    phone.connect(("127.0.0.1", 8080))
    while 1:
        data = input("请输入>>>")
        if not data:
            print("输入内容不为空!")
            continue
        phone.send(data.encode("utf-8"))
        if data.upper() == "Q":
            print("通信关闭!")
            break
    
        data_deposit = b""
        data_head = phone.recv(4)
        data_new = struct.unpack("i", data_head)[0]
        while len(data_deposit) < data_new:
            data_deposit += phone.recv(1024)
        print(data_deposit.decode("gbk"))
    phone.close()
    
    
  • 相关阅读:
    pro asp.net mvc5 7
    pro asp.net mvc5
    第九章 观察者模式 OBSERVER
    第八章 单件模式 singleton
    第二部分 职责型模式responsibility
    设计模式5 合成模式 COMPOSITE
    linux中xargs用法
    linux中du的用法
    linux中find的用法
    linux中grep注意
  • 原文地址:https://www.cnblogs.com/NiceSnake/p/11385856.html
Copyright © 2020-2023  润新知