python-day31-32_网络编程
1,UDP
UDP server必须先接收
server:
import socket sk = socket.socket(type=socket.SOCK_DGRAM) # 建立一个socket对象, # 指定以UDP协议的形式来连接 sk.bind(('127.0.0.1',8080)) # 指定服务的地址 msg,addr = sk.recvfrom(1024) # 接收消息,发送端的地址 print(msg,addr) sk.sendto(b'HELLO',addr) # 给发送端回复消息 sk.close() # 关闭socket连接
client:
import socket sk = socket.socket(type=socket.SOCK_DGRAM) sk.sendto(b'hello',('127.0.0.1',8080)) # 直接给服务器发送一段消息 msg,addr = sk.recvfrom(1024) # 接收对面的回信 print(msg) sk.close()
2,黏包问题
TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。
收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。
接收端只能按指定的缓冲区大小接收,超过缓冲区部分没有接收到的,会到下次继续接收----前提是会话没有中断。
解决办法1
server:
# 基于TCP实现远程执行命令 # 在server端下发命令 import socket sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen() conn,addr = sk.accept() while True: info = input('\033[1;33m请输入DOS命令:\033[0m') conn.send(info.encode('gbk')) if info == 'q':break lengh = conn.recv(1024).decode('gbk') conn.send(b'ack') ret = conn.recv(int(lengh)).decode('gbk') print(ret) conn.close() sk.close()
client:
import socket import subprocess sk = socket.socket() sk.connect(('127.0.0.1',8080)) while True: info = sk.recv(1024).decode('gbk') if info == 'q':break print('执行命令:',info) cmd = subprocess.Popen(info,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) res_stdout = cmd.stdout.read() # 本行如增加字符或进行编解码,会导致报错 res_stderr = cmd.stderr.read() sk.send(str(len(res_stdout)+len(res_stderr)).encode('gbk')) sk.recv(1024) sk.send(res_stdout) sk.send(res_stderr) print('执行结果:',res_stdout.decode('gbk'),res_stderr.decode('gbk')) sk.close()
要在文件中配置一个配置项:每一次recv的大小 buffer=4096
当我们要发送大量数据的时候,要明确告诉接收方要发送多大的数据,以便接收方能够准确的接收到所有数据。
多用在文件传输的过程中:
大文件的传输,一定是按照字节读,每一次读固定的字节
传输的过程中,一边读一边传;接收端,一边收一边写
send这个大文件,32768字节 send(4096) 32768-4096-4096 --> 0
recv这个大文件,recv 32768字节 recv(4096) 32768-4096-4096 --> 0
不好的地方:多了一次交互
send sendto 在超过一定范围的时候,都会报错
解决办法2
struct模块
该模块可以把一个类型,如数字,转成固定长度的bytes。表示的数字范围:-2147483648 <= number <= 2147483647
server
import struct import socket sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen() conn,addr = sk.accept() while True: cmd = input('\033[1;33m请输入DOS命令:\033[0m') conn.send(cmd.encode('gbk')) if cmd == 'q':break lengh = conn.recv(4) lengh = struct.unpack('i',lengh)[0] # 结果是元组数据类型 # conn.send(b'ack') ret = conn.recv(lengh).decode('gbk') print(ret) conn.close() sk.close()
client
import socket import subprocess import struct sk = socket.socket() sk.connect(('127.0.0.1',8080)) while True: info = sk.recv(1024).decode('gbk') if info == 'q':break print('执行命令:',info) cmd = subprocess.Popen(info,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) res_stdout = cmd.stdout.read() # 如增加字符或进行编解码,会导致报错 res_stderr = cmd.stderr.read() lengh = len(res_stdout)+len(res_stderr) sk.send(struct.pack('i',lengh)) # 把整数打包成4个字节长度的整型字节类型, # sk.recv(1024) sk.send(res_stdout) sk.send(res_stderr) print('执行结果:',res_stdout.decode('gbk'),res_stderr.decode('gbk')) sk.close()