Python中的网络编程

Python中的网络编程

B/S与C/S

  • S :Server 服务器端
  • C :Client 客户端
  • B :Browser 浏览器

互联网协议

  • TCP

    传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠 的、基于字节流的传输层通信协议。(注:摘自百度百科)

    • 三次握手

    • 四次挥手

      客户端主动向服务端发送断开请求,服务器发送消息代表已不再接收客户端消息。

      服务端等待传输任务结束后向客户端发送断开请求,客户端响应消息同时服务端我们断开连接,这个时候客户端会进入一个计时等待时间,假如这个时候服务端又发送了一条断开的消息,这个时候就说明之前发送的消息服务器没有收到,客户端就会再次发送断开响应。直到客户端在计时等待的时候没有收到服务端的消息了,那么客户端就可以关闭连接了。

  • UDP

    UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种 无连接 的传输层协议,提供面向事务的简单 不可靠 信息传送服务。(注:摘自百度百科)

Python基于TCP与UDP的网络编程

  • TCP

    • 客户端

      import socket
      soc=socket.socket()
      soc.connect(('127.0.0.1',8080))
      soc.send('hello hello'.encode())
      
      data=soc.recv(1024)
      print('我收到服务端回的',data.decode())
      
      soc.close()
      
    • 服务端

      import socket
      soc=socket.socket()
      soc.bind(('127.0.0.1',8080))
      soc.listen(5)
      conn,addr=soc.accept()
      
      data=conn.recv(1024)
      print('我收到客户端发的',data.decode())
      conn.send(data.decode().upper().encode())
      
      conn.close()
      soc.close()
      
  • UDP

    • 客户端

      import socket
      
      s = socket.socket(type=socket.SOCK_DGRAM)
      
      s.sendto('hello world!'.encode(),('127.0.0.1',8080))
      print('收到服务端消息',s.recvfrom(1024)[0].decode())
      
      s.close()
      
    • 服务端

      import socket
      
      s = socket.socket(type=socket.SOCK_DGRAM)
      s.bind(('127.0.0.1',8080))
      
      data = s.recvfrom(1024)
      print('收到客户端消息', data[0].decode())
      s.sendto(data[0].decode().upper().encode(), data[1])
      
      s.close()
      

TCP的粘包问题

只有TCP有粘包现象,UDP永远不会粘包,因为TCP是基于 数据流 的协议,而UDP是基于 数据报 的协议

为什么会发生粘包问题

因为接收方不知道消息与消息之间的界限,不知道一次性接收多少字节的数据所造成的。

如何解决粘包问题

模拟UDP的数据报形式

  • 服务端

    import socket
    import struct
    import json
    
    soc = socket.socket()
    soc.bind(('127.0.0.1', 8080))
    soc.listen(5)
    conn, addr = soc.accept()
    
    s_bytes = 'Hello Client!'.encode()
    # 创建头字典,将数据长度保存到字典中
    dic = {'size': len(s_bytes)}
    # 将字典转成bytes格式
    dic_bytes = (json.dumps(dic)).encode()
    # head_count是4个字节的长度
    head_count = struct.pack('i', len(dic_bytes))
    # 发送同步信息长度
    conn.send(head_count)
    # 发送头部内容
    conn.send(dic_bytes)
    # 发了内容
    conn.send(s_bytes)
    
    
    conn.close()
    soc.close()
    
    
  • 客户端

    import socket
    import struct
    import json
    
    s = socket.socket()
    s.connect(('127.0.0.1', 8080))
    
    # 头部字典长度固定4字节
    dic_bytes = s.recv(4)
    # 解出头部字典的长度
    dic_len = struct.unpack('i', dic_bytes)[0]
    # 接收头部字典
    str_dic = s.recv(dic_len)
    # 将字符串转成字典
    dic = json.loads(str_dic)
    # 获取数据长度
    data_len = dic['size']
    # 接收数据部分
    while data_len > 0:
        if data_len > 1024:
            print(s.recv(1024))
        else:
            print(s.recv(data_len))
        data_len -= 1024
    
    s.close()
    

多线程

  • 服务端

    import socket
    import struct
    import json
    import socketserver
    
    def read_data(con: socket.socket) -> str:
        pack = con.recv(4)
        head_size = struct.unpack('i', pack)[0]
        head_dic = json.loads(con.recv(head_size).decode())  # type:dict
        data_size = head_dic.get('data_size')
        data = b''
        while data_size > 0:
            if data_size > 1024:
                data += con.recv(1024)
            else:
                data += con.recv(data_size)
            data_size -= 1024
        return data.decode()
    
    def write_data(con: socket.socket, data: str):
        data_size = len(data.encode())
        data_hred = {'data_size': data_size}
        data_hred = json.dumps(data_hred).encode()
        con.send(struct.pack('i', len(data_hred)))
        con.send(data_hred)
        con.send(data.encode())
    
    class myTcp(socketserver.BaseRequestHandler):
        def handle(self):
            while True:
                data = read_data(self.request)
                print('收到客户端消息', data)
                write_data(self.request, data.upper())
    
    
    if __name__ == '__main__':
        s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), myTcp)
    
        s.serve_forever()
    
  • 客户端

    import socket
    import struct
    import json
    
    def read_data(con: socket.socket) -> str:
        pack = con.recv(4)
        head_size = struct.unpack('i', pack)[0]
        head_dic = json.loads(con.recv(head_size).decode())  # type:dict
        data_size = head_dic.get('data_size')
        data = b''
        while data_size > 0:
            if data_size > 1024:
                data += con.recv(1024)
            else:
                data += con.recv(data_size)
            data_size -= 1024
        return data.decode()
    
    def write_data(con: socket.socket, data: str):
        data_size = len(data.encode())
        data_hred = {'data_size': data_size}
        data_hred = json.dumps(data_hred).encode()
        con.send(struct.pack('i', len(data_hred)))
        con.send(data_hred)
        con.send(data.encode())
    
    if __name__ == '__main__':
        s = socket.socket()
        s.connect(('127.0.0.1', 8080))
        while True:
            write_data(s, 'hello world!')
            print(read_data(s))
    
原文地址:https://www.cnblogs.com/Gredae/p/11562021.html