第三十一天 udp通信和黏包
1.默写一下上节课的tcp通讯程序:
server端的程序;
import socket sk=socket.socket() #创建一个socket对象 sk.bind(('127.0.0.1',8090)) #给对象绑定一个ip和端口号 sk.listen() #进行监听 conn,addr=sk.accept()#获取一个客户端的连接,这一步已经完成了三次握手,这一步会产生堵塞 while True: ret=conn.recv(1024).decode('utf-8') #这一步也会产生堵塞 if ret=='bye': break print(ret) info=input('请输入信息:') if ret=='bye': break conn.send(info.encode('utf-8')) conn.close() sk.close()
client端的程序:
import socket sk=socket.socket() sk.connect(('127.0.0.1',8090)) while True: info=input('请输入信息:') if info=='bye': sk.send(b'bye') break info='alex'+info sk.send(info.encode('utf-8')) ret=sk.recv(1024).decode('utf-8') print(ret) if ret=='bye': break sk.close()
2.如果有两个客户端和一个服务器进行通讯(通讯协议选用tcp协议,并且先启动client1,那么client2先发送信息,server可以接受到吗?)
答:接受不到,当client启动之后,client1和server就建立了长连接,这个长连接是独自占用,只有当clent1断开之后才可以有其他的客户机于其交流
server端程序:
import socket sk=socket.socket() sk.connect(('127.0.0.1',8090)) while True: info=input('请输入信息:') if info=='bye': sk.send(b'bye') break info='tigger'+info sk.send(info.encode('utf-8')) ret=sk.recv(1024).decode('utf-8') print(ret) if ret=='bye': break sk.close()
client1端程序:
import socket sk=socket.socket() sk.connect(('127.0.0.1',8090)) while True: info=input('请输入信息:') if info=='bye': sk.send(b'bye') break info='alex'+info sk.send(info.encode('utf-8')) ret=sk.recv(1024).decode('utf-8') print(ret) if ret=='bye': break sk.close()
client2端程序:
import socket sk=socket.socket() sk.connect(('127.0.0.1',8090)) while True: info=input('请输入信息:') if info=='bye': sk.send(b'bye') break info='tigger'+info sk.send(info.encode('utf-8')) ret=sk.recv(1024).decode('utf-8') print(ret) if ret=='bye': break sk.close()
3.使用udp协议进行通讯的程序:
server端的程序:
import socket sk=socket.socket(type=socket.SOCK_DGRAM)#创建对象,括号里面加上类型 sk.bind(('127.0.0.1',8080)) #绑定ip和端口号 while True: ret,addr=sk.recvfrom(1024) #udp必须先要接受数据,为了获取返送端的地址 print (addr) print(ret.decode('utf-8')) info =input('请输入一个信息:') info=info.encode('utf-8') sk.sendto(info,addr) #数据的发送 sk.close()
client端的程序:
import socket sk=socket.socket(type=socket.SOCK_DGRAM) ip_port =('127.0.0.1',8080) while True: info=input('请输入信息:') info=('\033[34m;%s:%s\033[0m'%('alxe',info)).encode('utf-8') sk.sendto(info,ip_port) ret,addr=sk.recvfrom(1024) print(ret.decode('utf-8')) sk.close()
client2端的程序:
import socket sk=socket.socket(type=socket.SOCK_DGRAM) ip_port =('127.0.0.1',8080) while True: info=input('请输入想要发的信息:') info=('\033[32m;%s:%s\033[0m'%('tigger',info)).encode('utf-8') sk.sendto(info,ip_port) ret,addr=sk.recvfrom(1024) print(ret.decode('utf-8')) sk.close()
4.subprocess 模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。
import subprocess res=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) ret=res.stdout.read() ret1=res.stderr.read().decode('gbk') print(ret)#输出数据时bytes类型 ret=ret.decode('gbk') print('stdout',ret) print('stdeer',ret1) 结果为 b' \xc7\xfd\xb6\xaf\xc6\xf7 D \xd6\xd0\xb5\xc4\xbe\xed\xca\xc7 DATA\r\n \xbe\xed\xb5\xc4\xd0\xf2\xc1\xd0\xba\xc5\xca\xc7 5CB4-94EB\r\n\r\n D:\\python\xc1\xb7\xcf\xb0\xb3\xcc\xd0\xf2\\\xb5\xda\xc8\xfd\xca\xae\xd2\xbb\xcc\xec\\demo4 \xb5\xc4\xc4\xbf\xc2\xbc\r\n\r\n2020/03/05 16:40 <DIR> .\r\n2020/03/05 16:40 <DIR> ..\r\n2020/03/05 16:15 304 client1.py\r\n2020/03/05 16:15 318 client2.py\r\n2020/03/05 16:40 269 practise.py\r\n2020/03/05 16:18 435 server.py\r\n2020/03/05 15:49 0 __init__.py\r\n 5 \xb8\xf6\xce\xc4\xbc\xfe 1,326 \xd7\xd6\xbd\xda\r\n 2 \xb8\xf6\xc4\xbf\xc2\xbc 43,053,735,936 \xbf\xc9\xd3\xc3\xd7\xd6\xbd\xda\r\n' stdout 驱动器 D 中的卷是 DATA 卷的序列号是 5CB4-94EB D:\python练习程序\第三十一天\demo4 的目录 2020/03/05 16:40 <DIR> . 2020/03/05 16:40 <DIR> .. 2020/03/05 16:15 304 client1.py 2020/03/05 16:15 318 client2.py 2020/03/05 16:40 269 practise.py 2020/03/05 16:18 435 server.py 2020/03/05 15:49 0 __init__.py 5 个文件 1,326 字节 2 个目录 43,053,735,936 可用字节 stdeer
5.看下面这段程序我们可以发现什么问题:
server端:
import socket sk=socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen() conn,addr=sk.accept() while True: cmd=input('>>>') conn.send(cmd.encode('utf-8')) ret= conn.recv(1024).decode('utf-8') print(ret) conn.close() sk.close()
client端:
import socket import subprocess sk=socket.socket() sk.connect(('127.0.0.1',8080)) while True: cmd=sk.recv(1024).decode('gbk') ret=subprocess.Popen(cmd,shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) std_out='stdout:'+(ret.stdout.read()).decode('gbk') std_err='stderr'+(ret.stderr.read()).decode('gbk') sk.send(std_out.encode('utf-8')) sk.send(std_err.encode('utf-8')) sk.close()
通过结果我们不难看出发送的数据和接受的数据已经乱了,有时候出现接受过多的问题,有时候出现节后不玩的问题,这些问题我都都称之为黏包问题。
6.对于udp来说如果出现数据量过大的情况又会有什么问题那:
import socket sk=socket.socket(type=socket.SOCK_DGRAM)#创建对象,括号里面加上类型 sk.bind(('127.0.0.1',8080)) #绑定ip和端口号 while True: ret,addr=sk.recvfrom(1024) #udp必须先要接受数据,为了获取返送端的地址 print(ret.decode('utf-8')) info =input('请输入一个信息:') info=info.encode('gbk') sk.sendto(info,addr) #数据的发送 sk.close()
client
import socket import subprocess sk=socket.socket(type=socket.SOCK_DGRAM) ip_port =('127.0.0.1',8080) while True: info=input('请输入信息:') info=info.encode('utf-8') sk.sendto(info,ip_port) ret,addr=sk.recvfrom(1024) ret=ret.decode('gbk') ret=subprocess.Popen(ret,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) std_out='std_out:'+(ret.stdout.read()).decode('gbk') std_err='std_err:'+(ret.stderr.read()).decode('gbk') sk.sendto(std_out.encode('utf-8'),ip_port) sk.sendto(std_err.encode('utf-8'),ip_port) sk.close()
从结果发现:我们会把多余的数据量丢弃。
7.tcp'中