一.粘包
只有tcp协议才会发生粘包,udp不会 在tcp协议中:
有一个合包机制(nagle 算法),将多次连续发送且间隔小的数据,将其打包一块数据传送
还有一个机制就是拆包机制,因为受到网卡的MTU限制的数据,进行拆分,拆分成多个小的数据,进行传输
当传输到目标主机的操作系统层时,会重新将多个小的数据合并成原本的数据
为什么udp不会发生粘包?
udp不会发生粘包,udp协议本层对一次收发数据大小的限制是: 65535 - IP包头(20) - udp包头(8) = 65507 站在数据链路层,应为网卡的MTU一般限制在了1500,所以对于数据链路层来说,一次发数据的大小被限制在 1500 - ip包头(20) - udp包头(8) = 1472 得到的结论: 如果sendto(num) num > 65507 报错 1472 < num < 65507 会在数据链路层拆包,而udp本身就是不可靠的协议, 一旦拆包之后,造成的多个小数据包在网络传输中,如果丢任何一个,那么此次数据传输失败 num < 1472 是比较理想的状态
二.执行命令(subprocess)
cmd = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) # cmd : 代表系统命令 # shell = True : 代表这个命令是 系统命令;告诉操作系统,把cmd当成系统命令执行 # stdout : 是执行完系统命令之后,用于保存结果的一个管道 # stderr : 是执行完系统命令之后,用于保存错误的一个管道
服务器端:
import socket import subprocess sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen() conn,addr = sk.accept() while 1: msg_r = conn.recv(1024).decode('utf-8') result = subprocess.Popen(msg_r,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) # print(result.stdout.read().decode('gbk')) # print(result.stderr.read()) stdout = result.stdout.read() stderr = result.stderr.read() if stderr: conn.send(stderr) else: conn.send(stdout) conn.close() sk.close()
客户端:
''' 客户端发送要执行命令 服务器执行命令,将执行的结果返回给客户端 客户端拿到结果呈现到用户眼前 ''' import socket sk = socket.socket() sk.connect_ex(('127.0.0.1',8080)) while 1: cmd = input('请输入系统命令>>>') sk.send(cmd.encode('utf-8')) msg_r = sk.recv(10240).decode('gbk') print(msg_r) sk.close()
三.大文件传输
服务器端:
import socket import json import struct sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen() conn,addr = sk.accept() # str_dic = conn.recv(100).decode('utf-8') # dic = json.loads(str_dic) # print(dic) b_len_dic = conn.recv(4) len_dic = struct.unpack('i',b_len_dic)[0] str_dic = conn.recv(len_dic).decode('utf-8') dic = json.loads(str_dic) print(dic) # conn.send(b'OK') if dic['opt'] == 'upload': filename = '1' + dic['filename'] with open(filename,mode='ab') as f: while dic['filesize']: content = conn.recv(1024) f.write(content) dic['filesize'] -= len(content) conn.close() sk.close()
客户端:
import socket import os import json import struct sk = socket.socket() sk.connect_ex(('127.0.0.1',8080)) meau = {'1':'upload','2':'download'} num = input('请输入选项功能>>>') dic = {'opt':meau.get(num),'filename':None,'filesize':None} file_path = input('请输入一个绝对路径>>>') filename = os.path.basename(file_path) dic['filename'] = filename filesize = os.path.getsize(file_path) dic['filesize'] = filesize str_dic = json.dumps(dic) len_dic = len(str_dic) b_len_dic = struct.pack('i',len_dic) # 将字典的长度打包成一个4bytes的数据 sk.send(b_len_dic+str_dic.encode('utf-8')) # sk.recv(1024) # 为什么要在这里加上一个recv?主要是防止上一个send程序执行过快,导致下面send程序与其发生粘包,从而发生数据混乱现象 with open(file_path,mode='rb') as f: while filesize: content = f.read(1024) sk.send(content) filesize -= len(content) sk.close()
四.切换目录
服务器端:
import socket import os sk = socket.socket() sk.bind(('127.0.0.1', 8080)) sk.listen() conn, addr = sk.accept() def send_data(conn, path): lis_dir = os.listdir(path) str_dir = '__'.join(lis_dir) conn.send(str_dir.encode('utf-8')) abs_path = conn.recv(1024).decode('utf-8') current_dir = abs_path send_data(conn, current_dir) while 1: cmd = conn.recv(1024).decode('utf-8') if cmd == '..': current_dir = '/'.join(current_dir.split('\\')[:-1]) print(current_dir) send_data(conn,current_dir) else: filename = cmd.split(' ')[1] print(filename) current_dir = current_dir + '//' + filename print(current_dir) if os.path.isdir(current_dir): send_data(conn,current_dir) else: conn.send('不是一个文件夹名'.encode('utf-8')) conn.close() sk.close()
客户端:
import socket import os sk = socket.socket() sk.connect_ex(('127.0.0.1', 8080)) abs_path = input('请输入您的根目录>>>') sk.send(abs_path.encode('utf-8')) current_dir = sk.recv(1024).decode('utf-8') print(current_dir.split('__')) while 1: cmd = input('>>>') if cmd == '..': sk.send(cmd.encode('utf-8')) current_dir = sk.recv(1024).decode('utf-8') print(current_dir.split('__')) elif cmd == 'cd': filename = input('请输入一个文件夹名>>>') sk.send((cmd+' '+filename).encode('utf-8')) current_dir = sk.recv(1024).decode('utf-8') print(current_dir.split('__')) sk.close()