• 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))
      
  • 相关阅读:
    多线程访问成员变量与局部变量
    Could not resolve placeholder 解决方案
    instanceof, isinstance,isAssignableFrom的区别
    YYYY-mm-dd HH:MM:SS
    整合Spring Data JPA与Spring MVC: 分页和排序
    dubbo配置文件xml校验报错
    安装eclipse插件时出现问题
    Windows上搭建hadoop开发环境
    jquery validate 在ajax提交表单下的验证方法
    HDU 1698 Just a Hook(线段树区间替换)
  • 原文地址:https://www.cnblogs.com/Gredae/p/11562021.html
Copyright © 2020-2023  润新知