Python网络编程day-2[socket(udp),粘包,简单文件传输]
UDP模式的socket:
自带迸发连接。
因为是udp连接所以不可靠
服务端: import socket ip = ('127.0.0.1',5333) server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) server.bind(ip) while True: msg,addr = server.recvfrom(1024) print('recv:',msg,addr) server.sendto('This is udp scoket server'.encode('utf-8'),addr) 客户端: import socket ip = ('127.0.0.1',5333) client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) while True: msg = input('>>>: ').strip() if not msg:continue client.sendto(msg.encode('utf-8'),ip) server_msg,addr = client.recvfrom(1024) print(server_msg.decode('utf-8'),addr)
粘包问题:
比如我们在写一个简单的ssh socket程序时,在远程的计算机执行命令返回结果 过长的命令时,会有粘包现象(命令结果一次传输不完,输入下条命令显示的是上一条命令未传输完的结果。)
造成粘包的问题,是因为命令在执行完结果是保存在 cache中的。
服务端: import time import socket import subprocess sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.bind(("",9998)) sock.listen(1) while True: conn,addr = sock.accept() #等待、阻塞 print("got a new customer",conn,addr) while True: data = conn.recv(1024) #等待 bytes print("received",data) if not data: #客户端断开了 print("conn %s is lost" % str(addr) ) conn.close() #清除了跟这个断开的链接的实例对象 break #conn.send(data.upper() ) cmd = subprocess.Popen(data.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = cmd.stdout.read() stderr = cmd.stderr.read() cmd_res = stdout + stderr if not cmd_res: cmd_res = b'cmd has not output' msg_header = str(len(cmd_res)).zfill(10) #定义 消息头 长度为 10 不足10 使用 数字零填充 conn.send( bytes(msg_header,encoding='utf-8') ) #发送数据头 #conn.recv(1) #给用户发送完信息了等待用户返回 信息接收完的消息 #time.sleep(0.5) #这种方式是直接 暂停程序 0.5秒 等待 cache 刷新 conn.sendall(cmd_res) #不能发空消息 sock.close() #关闭端口和服务
简单的文件传输:
服务端: import socket import os,json sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.bind(("",9999)) sock.listen(1) def pack_msg_header(header,header_size): #文件信息字典处理函数 接收字典和字典指定大小参数 bytes_header = bytes(json.dumps(header) ,encoding="utf-8") #转换文件信息字典为 bytes if len(bytes_header ) < header_size :#需要补充0 # 计算下变成字节的字典长度 并与指定的字典大小做比较,如果字典小于指定数值 header['fill'].zfill( header_size - len(bytes_header) ) #向 字典中的 fill 元素 补充对应的零 bytes_header = bytes(json.dumps(header), encoding="utf-8") #重新 转换 更改后的字典 return bytes_header #返回更改后的字典 while True: conn,addr = sock.accept() #等待、阻塞 print("got a new customer",conn,addr) while True: raw_cmd = conn.recv(1024) # get test.log #接收用户输入的指令 cmd,filename = raw_cmd.decode("utf-8").split() #切分用户输入的指令 并赋值cmd 和 filename if cmd == "get": #如果cmd 为 get msg_header = {"fill": ''} #创建字典,并初始创建一个fill元素用于控制头文件大小 if os.path.isfile(filename): #判断文件是否存在 msg_header["size"] = os.path.getsize(filename) #获取文件大小并添加到字典中 msg_header["filename"] = filename #获取文件名并添加到字典中 msg_header["ctime"] = os.stat(filename).st_ctime bytes_header = pack_msg_header(msg_header,300) #调用函数并接收返回值 conn.send(bytes_header) #发送给客户端 头部信息 f = open(filename,"rb") #以字节模式打开 客户端请求的文件 for line in f: #循环取出文件内容并发送 conn.send(line) else: #如果文件发送完毕 则 打印信息 print("file send done....") f.close() #操作文件完毕关闭文件 else: # <============================:如果文件判断不存在则发送相应的信息给客户端 msg_header['error'] = "file %s on server does not exist " % filename bytes_header = pack_msg_header(msg_header, 300) conn.send(bytes_header) sock.close() #关闭端口和服务 客户端: import socket import json ,os sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #数据流 sock.connect(('192.168.16.131',9999)) while True: cmd = input(">>>:").strip() if not cmd : continue sock.send(cmd.encode("utf-8")) msg_header = sock.recv(300) #接收信息头 header = json.loads(msg_header.decode("utf-8")) #反序列化取出文件的字典形式信息 if header.get("error"): print(header.get("error")) else: filename = header['filename'] #提取字典的值 file_size = header['size'] f = open(filename,"wb") received_size = 0 while received_size < file_size : #切片传输 一次接收8192 字节 if file_size - received_size < 8192:#last time #最后一次传输不足 8192 则计算剩余的大小接收 data = sock.recv(file_size - received_size) else: data = sock.recv(8192) received_size += len(data) #已接收的文件大小 自增 f.write(data) #写入文件 #print("recv",received_size,file_size) #显示 文件的接收过程 因为调用屏幕显示 会减慢传输速度 else: print("file receive done....",filename,file_size) #传输完毕打印完成 f.close() #关闭文件 sock.close()
浙公网安备 33010602011771号