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()