• 网络编程笔记(2)——socket长连接、黏包问题、subprocess模块


    内容目录:

    • tcp协议的socket长连接
    • 基于udp协议的socket连接
    • 黏包问题
    • subprocess模块

    内容详细

    1.tcp协议的socket长连接

    • 长连接只能保持和一个client端连接,第一个断开连接后才能和后面的一个客户端连接
    #Server端
    import socket
    sk = socket.socket()        #拿到socket的句柄
    sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    sk.bind(('127.0.0.1',8080))
    sk.listen()                 #监听是否有通信
    while True:
        conn,addr = sk.accept()     #接收到client:连接:connection,地址:address
    
        print(addr)
        while True:
            ret = conn.recv(1024).decode('utf-8')       #接收到1024个字节,如果更改,必须为1024的倍数
            print(ret)
            if ret == 'bye':
                break
            info = input(">>>:")
            if info == 'bye':
                conn.send(b'bye')
                break
            conn.send(bytes(info,encoding='utf-8'))     #和client传信息,必须传一个byte类型
    
        conn.close()                #连接断开
    sk.close()
    
    #Client端--第一个客户端
    import socket
    sk = socket.socket()
    sk.connect(('127.0.0.1',8080))
    while True:
        info = input('client2>>>:')
        if info == 'bye':
            sk.send(b'bye')
            break
        sk.send(bytes(info.encode('utf-8')))
        ret = sk.recv(1024).decode('utf-8')
        print(ret)
        if ret == 'bye':
            sk.send(b'bye')
            break
    sk.close()
    
    #多个client端--代码如第一个客户端
    

    2.基于udp协议的socket连接

    • UDP的server 不需要进行监听也不需要建立连接

    • 在启动服务之后只能被动的等待客户端发送信息过来

    • 客户端发送消息的同时还会自带地址信息

    • 消息回复的时候,不仅需要发送消息,还需要把目标的地址带上

      #Srever端
      import socket
      sk = socket.socket(type=socket.SOCK_DGRAM)        #DGRAM datagram基于UDP协议
      sk.bind(('127.0.0.1',8080))
      
      msg,addr = sk.recvfrom(1024)
      print(msg.decode('utf-8'))
      sk.sendto(b'bye',addr)
      
      sk.close()
      
      #Client端
      import socket
      sk = socket.socket(type=socket.SOCK_DGRAM)
      ip_port = ('127.0.0.1',8080)
      
      sk.sendto(b'hello',ip_port)
      ret,addr = sk.recvfrom(1024)
      print(ret.decode('utf-8'))
      
      sk.close()
      
    • 同时多个客户端聊天

      #Server:
      import socket
      sk = socket.socket(type=socket.SOCK_DGRAM)        #DGRAM datagram基于UDP协议
      sk.bind(('127.0.0.1',8080))
      
      while True:
          msg,addr = sk.recvfrom(1024)
          print(msg.decode('utf-8'))
          if msg == 'bye':
              break
          info = input('Server:')
          info = ('33[31mServer:%s33[0m'%info).encode('utf-8')
          sk.sendto(info,addr)
      sk.close()
      
      #Client1:
      import socket
      sk = socket.socket(type=socket.SOCK_DGRAM)
      ip_port = ('127.0.0.1',8080)
      while True:
          info = input('Client1:')
          info = ('33[32m来自Client1的消息:%s33[0m'%info).encode('utf-8')
          sk.sendto(info,ip_port)
          ret,addr = sk.recvfrom(1024)
          print(ret.decode('utf-8'))
          if ret == 'bye':
              break
      
      sk.close()
      
      #Client:
      import socket
      sk = socket.socket(type=socket.SOCK_DGRAM)
      ip_port = ('127.0.0.1',8080)
      while True:
          info = input('Client2:')
          info = ('33[34m来自Client2的消息:%s33[0m'%info).encode('utf-8')
          sk.sendto(info,ip_port)
          ret,addr = sk.recvfrom(1024)
          print(ret.decode('utf-8'))
          if ret == 'bye':
              break
      
      sk.close()
      

    3.黏包问题

    • 使用TCP协议连接时:

      • 会出现黏包现象:信息过长,接收的不完整,如果没接完上一条信息则执行下一命令时会继续打印上一条信息
      • 不会丢包,信息可靠
    • 使用UDP协议连接时:

      • 信息接收不可靠,如果信息过长,则执行完命令后,多余信息直接抛弃
      • 会丢包
    • 所有的客户端执行server端下发的指令

    • 将所有的执行结果反馈回来,我来接收

      #例子:设置时间服务器
      # server端:
      # 需求
          # 写一个时间同步的服务器
          # 服务端接收请求
          # 按照client端发送的时间格式,将服务器时间转换成对应格式
          # 发送给客户端
      import time
      import socket
      
      sk = socket.socket(type=socket.SOCK_DGRAM)
      sk.bind(('127.0.0.1',9000))
      while True:
          msg,addr = sk.recvfrom(1024)
          # msg 客户端发送给server端的时间格式 "%Y-%m-%d %H:%M-%S"
          time_format = msg.decode('utf-8')
          time_str = time.strftime(time_format)
          sk.sendto(time_str.encode('utf-8'),addr)
      sk.close()
      
      #Client端:
      # client端每隔一段时间发送请求到服务端
      # 发送时间的格式
      import time
      import socket
      sk = socket.socket(type = socket.SOCK_DGRAM)
      sk.sendto('%Y-%m-%d %H:%M:%S'.encode('utf-8'),('127.0.0.1',9000))
      msg,addr = sk.recvfrom(1024)
      print(msg.decode('utf-8'))
      sk.close()
      
      # 方式一
      # 操作系统的定时任务 + python代码的形式
      # 方式二
      # while True + time.sleep的形式
      

    4.subprocess模块

    • 读取系统命令的模块

      #Client端:
      import socket
      import subprocess
      
      sk = socket.socket()
      sk.connect(('127.0.0.1',8080))
      
      cmd = sk.recv(1024).decode('gbk')   #因为Windows传输都为GBK编码的
      res = subprocess.Popen(cmd,shell=True,          #PIPE为管道/队列,只能取一次,取完就结束了
                             stdout=subprocess.PIPE,  #stdout为命令的输出
                             stderr=subprocess.PIPE)  #stderr为命令错误的提示信息
      std_out = res.stdout.read() #从队列中取出命令
      std_err = res.stderr.read() #从队列中取出错误命令信息
      sk.send(std_out)
      sk.send(std_err)
      
      sk.close()
      
  • 相关阅读:
    Hadoop学习路线图
    windows命令——taskmgr 1
    windows命令——explorer
    windows命令——taskkill
    struts tags
    jsp的 javascript中 嵌套 html 注释
    netstat
    没有、不愿、不能足够交流、沟通的开发、测试,将是悲剧
    linux java so 历险
    linux java 版本
  • 原文地址:https://www.cnblogs.com/lynlearnde/p/13471634.html
Copyright © 2020-2023  润新知