udp和黏包问题

udp

服务端

 import socket
 ​
 # 1. 创建对象
 sk = socket.socket(type=socket.SOCK_DGRAM)  # SOCK_STREAM: TCP   SOCK_DGRAM:UDP
 ​
 # 2.绑定地址端口
 sk.bind(('127.0.0.1', 9000))
 ​
 # 3.upd服务器,在一开始只能够接收数据
 while True:
     # 接收数据
     msg, cli_addr = sk.recvfrom(1024)
     print(msg.decode('utf-8'))
 ​
     message = input("客户端给服务端发送的消息是?:")
     # 发送数据
     sk.sendto(message.encode('utf-8'), cli_addr)
 ​
 # 4.关闭连接
 sk.close()

客户端

 import socket
 ​
 # 1 .创建对象
 cl = socket.socket(type=socket.SOCK_DGRAM)
 ​
 # 2.收发数据的逻辑
 while True:
     # 发送数据
     message = input('服务端给客户端发送的消息是:?')
     cl.sendto(message.encode('utf-8'), ('127.0.0.1', 9000))
 ​
     # 接收数据
     msg,addr = cl.recvfrom(1024)
     print(msg.decode('utf-8'))
 ​
 ​
 # 3.关闭连接
 cl.close() 

案例

写一个cs架构的软件,在客户端里面输入一个字符串,发送给服务器解析 成一个 命令执行,将执行结果发送给客户端

命令:把你原来点击鼠标的行为 变成命令

 windows
     dir:查看某一个文件夹下的子文件名与子文件夹名
     ipconfig:查看本地网卡信息
     tasklist:查看运行的程序
    
 linux
     ls:查看某一个文件夹下的子文件名与子文件夹名
     ifconfig:查看本地网卡信息
     ps aux:查看运行的程序

黏包

1.cmd:tasklist 这个命令特点就是特别特别的长 当我们再去输入dir的时候就会发现 还是原来的那个命令的结果

当我们执行一条特别长的命令的时候 你会发现你拿到的不是你需要的命令结果 而是上一条的残留

send 和 recv的原理:

1.不管recv还是send 他们都不是直接给对双方发送数据 而是通过操作系统

recv:

等待数据

复制数据

send

复制数据

2.不是一个send对应一个recv 因为send是在往自己的操作系统里面读数据,操作系统什么时候发 怎么发 我们都是管不了的

tcp协议在发送数据的时候,会使用一个优化 算法nagle 把多次间隔小的或者数据量小的数据合并成一个大的数据发送

3.黏包这种问题不会出现在UDP里面\

4.解决黏包的思路 在你不知道别人给你发多少的时候 分多次收 这样就不会出现黏包问题

解决黏包问题

服务端

 import socket
 import subprocess
 import struct
 ​
 server = socket.socket()
 server.bind(('127.0.0.1', 9000))
 server.listen(10)
 ​
 while True:  # 连接循环
     conn, addr = server.accept()
     print(addr)
     while True:  # 通信循环
         try:
             # 1.接收命令
             cmd = conn.recv(1024)
             if not cmd:
                 break
             print("接收到客户端的数据", cmd)
             # 2.执行命令
             obj = subprocess.Popen(cmd.decode('utf-8'), shell=True,   # shell=True 相当于启动cmd来执行前面的字符串
                                    stdout=subprocess.PIPE,  # 正确的结果
                                    stderr=subprocess.PIPE,  # 接收错误的结果
                                    )
             stdout = obj.stdout.read()
             stderr = obj.stderr.read()
             print(len(stdout+stderr))
             # 3.把命令执行的结果返回给客户端
             # 3.1 制作一个固定的报头
             total_size = len(stdout+stderr)
             header = struct.pack("i", total_size)
             # 3.2 把报头发送给客户端
             conn.send(header)
             # 3.3 发送真实数据
             conn.send(stdout)
             conn.send(stderr)
         except ConnectionResetError:
             break
 ​
     conn.close()

客户端

 import socket
 import struct
 ​
 client = socket.socket()
 client.connect(('127.0.0.1', 9000))
 ​
 while True:
     # 1.发送命令
     cmd = input(">>>").strip()
     if not cmd:
         continue
     if cmd == 'q':
         break
     # 2.发送命令
     client.send(cmd.encode('utf-8'))
 ​
     # 3.拿到命令的执行结果
     # 3.1 先拿到报头
     header = client.recv(4)
     total_size = struct.unpack('i',header)[0]
     # 3.2 接收真实的数据
     recv_size = 0
     recv_data = b''
     while recv_size < total_size:
         res = client.recv(1024)
         recv_data += res
         recv_size += len(res)
 ​
     print(recv_data.decode('gbk'))
 client.close()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值