信息图表设计网站,phpcms v9网站模板,工信部网站备案,阿里云如何购买域名套接字#xff1a;就是将传输层以下的协议封装成子接口对于应用程序来说只需调用套接字的接口#xff0c;写出的程序自然是遵循tcp或udp协议的实现第一个功能个#xff1a;实现#xff1a;通过客户端向服务端发送命令#xff0c;调取windows下面的cmd窗口#xff0c;将服…套接字就是将传输层以下的协议封装成子接口对于应用程序来说只需调用套接字的接口写出的程序自然是遵循tcp或udp协议的实现第一个功能个实现通过客户端向服务端发送命令调取windows下面的cmd窗口将服务端执行命令的结构返回并显示在客户端窗口上。subprocess:1.可以将执行结果返回2.返回值是bytes类型(基于这两点可以应用在server端将服务端的返回直接以bytes的格式直接send给客户端实现在客户端的显示)问题1粘包问题粘包问题实际是由TCP协议在传输数据时的2大特性来的TCP协议又叫流式协议在数据传输上只要客户端发送相应的数据请求服务端会将数据像流水一样不断的send给客户端基于这个特点就会存在一个问题当客户端给服务端发送一条命令服务端成功接收并将命令的结果返回到客户端的时候由于客户端recv()的数量限制可以一次不能完全取出这个时候就会存在下次输入命令客户端首先拿到的返回值就是上次残留的没有收完的数据基于粘包问题的解决思路就是发数据之前先把报头发给对方让对方先知道要收的报头的长度后面再传数据文件自定义报头为甚么要自定义报头因为struck path(‘i’3443242)1.’i‘:类型不同后面数字的长度大小也不同大小是有限的(当超出范围时会报错)2.因为报头里面含有的内容可能不仅仅只有total_siz还有filename、hash等等知识单纯的把total_size当做报头传入不合理所以我们要自定义报头Server端配置from socket import *importsocket,subprocess,struct,jsonserversocket.socket(AF_INET, SOCK_STREAM)server.bind((127.0.0.1, 8080))server.listen(5)whileTrue:conn,clientserver.accept()print(client)whileTrue:try:cmd conn.recv(1024)if len(cmd) 0: breakobjsubprocess.Popen(cmd.decode(utf-8),shellTrue,stdoutsubprocess.PIPE,stderrsubprocess.PIPE,)outobj.stdout.read()errobj.stderr.read()#制作报头header_dic{filename:a.txt,total_size:len(out)len(err),hash:abc32i5o24}#对包头进行序列化header_jsonjson.dumps(header_dic) #字符串格式header_bytesheader_json.encode(utf-8)#1.先发型报头的长度 len(header_bytes) struck为固定的4个字节conn.send(struct.pack(i,len(header_bytes)))#2.发送报头conn.send(header_bytes)#3.发送真是数据conn.send(out)conn.send(err)exceptConnectionResetError:breakconn.close()server.close()Client端配置from socket import *importsocket,struct,jsonclientsocket.socket(AF_INET,SOCK_STREAM)client.connect((127.0.0.1,8080))whileTrue:cmdinput(输入你要操作的命令)client.send(cmd.encode(utf-8))if len(cmd) 0:continue#1.先收报头的四个字节首先拿到报头传来的长度-》bytesheaderclient.recv(4) #i类型足够了 header为bytes类型header_sizestruct.unpack(i,header)[0] #拿到元祖形式取第一个就是整个报头的长度 print(header_size) #为报头的长度值#2.再收报头(对应服务端的conn.send(header_bytes))header_bytesclient.recv(header_size) #根据报头的固定长度去收接收#3.解析包头(就是将header_bytes文件先解码成json格式)header_strheader_bytes.decode(utf-8)header_dicjson.loads(header_str)print(header_dic)total_sizeheader_dic[total_size]print(total_size)recv_size0 #定义一个初始的接收变量为0只是个计数变量为了统计与总的total_size的len大小resbwhile recv_size recv_dataclient.recv(1024) #每次传过来的recv_data是bytes类型resrecv_datarecv_sizelen(recv_data) #循环增加每次接收值的长度#cmdclient.recv(1024)print(res.decode(gbk))client.close()粘包问题的最终解决方案分析服务端目的为了自定义报头(报头中不仅包含长度可能还有文件名等信息)subprocess...1.制作报头(字典形式)header_dic{filename:a.txt,total_size:len(out)len(err),hash:abc32i5o24}2.通过json将报头序列化再encode为bytes类型header_jsonjson.dumps(header_dic) #字符串类型header_bytesheader_json.encode(utf-8) #bytes类型3.发送报头的长度struck目的是固定封装好的报头为4个字节长度 对应客户端刚开始 headerclient.recv(4)struck:1.将数字转为bytes类型保证发送过去的是bytes类型 2.固定4个字节第一次发conn.send(struck.pack(i,len(header_bytes)))先传给客户端固定了收的时候报头的长度不至于报头和其他内容粘在一起4.发送报头 对应客户端接收报头 header_bytesclient.recv(header_size)第二次发conn.send(header_bytes)5.发送真实的数据conn.send(out)conn.send(err)客户端(bytes--int)1.通过服务端返回的字节拿到报头的的长度headerclient.recv(4) #header是4个bytes字节header_sizestruck.unpack(i,header)[0] #字节头-拿到int大小2.再收报头header_bytesclient.recv(header_size) #bytes类型3.解析报头(1.先把内存中存放的bytes类型用decode(utf-8)解码为字符串)header_jsonheader_bytes.decode(utf-8)header_dicjson.loads(header_json) #json反序列化出字典格式 (对应server第2步)print(header_dic)4.拿到字典中的报头大小total_sizeheader_dic[total_size]print(total_size)struck功能辅助理解所以客户端刚开始接收4 大小是足够把报头接收完的。#struck工鞥理解importstruct#将整型转成bytesresstruct.pack(i,1232435436)print(res,len(res)) #res:为bytes类型,还是固定长度4(一般情况已经可以包含很多)#将bytes转成整型aastruct.unpack(i,res)print(aa,aa[0],type(aa)) #print(len(res)) #4 一般情况多数bytes 4个长度足够了结果b\xecxuI 4(1232435436,) 1232435436 4