开发的第二阶段 网络编程阶段
之所以叫网络编程,是因为,这里面就不是你在一台机器中玩了.多台机器,CS架构.即客户端和服务器端通过网络进行通信的编程了.
首先想实现网络的通信,你得先学网络通信的一个基础,即两台机器之间是怎么打通的.有的同学说机器有IP地址,能互相ping通就连上了.
7层网络协议,第三层:网络层,第四层,传输层(tcp/ip协议).tcp/ip协议保证了两台机器的通信的可靠的数据传输(tcp/ip协议通信的3次握手).什么叫可靠的. A给B发消息,A发了,A会知道发没发到.
UDP不是可靠的数据传输协议,当A给B发消息,A发送出去了,A不知道B收没收到.A也不管.
UDP依然在使用.因为它快.
tcp/ip传输协议在发送数据前进行建立链接的3次握手.
3次握手后,才进行真正发送数据.那么问题来了.是什么东西在负责发送数据,对方又是什么东西在进行数据接收呢.那就是socket.
socket可以简单直白的认为它是一个管道,具体你在管道里传输什么socket不关心,如:mysql,http,这些对于socket来说就是一辆车.
Socket 基础
socket 通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求.
socket起源于Unix,而Unix/Linux 基本哲学之一就是"一切皆文件",对于文件用[打开][读写][关闭]模式来操作.
socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO\打开\关闭)
socket和file的区别:
file模块是针对某个指定文件进行[打开][读写][关闭]
socket 模块是针对 服务器端 和 客户端socket 进行 [打开][读写][关闭]
socket基础使用实例:
socket_server.py
import socket
ip_port = ('127.0.0.1',9999) sk = socket.socket() #创建一个socket的句柄,如同open()一个文件sk.bind(ip_port) #使用bind()方法,向系统内核注册一个ip,端口 作为这个socket的ip,port的属性,如果此端口没被占用,则
返回含有ip和端口的句柄,如果被占用则报错退出程序sk.listen(5) #这个socket句柄处于监听状态。while True: #写一个死循环,用来接收客户端对socket的链接请求print('server waiting ......')conn,addr = sk.accept()
#程序执行到accept()时,阻塞在这里,当客户端使用connect()方法,发送连接请求,accept()方法把客户端的ip也就是addr作为参数,传入sk这个socket实例设置了客户端的ip端口属性,然后把返回实例的内存地址,赋值给新的变量conn。语法就是conn,addr = 实例名.accept()。client_data = conn.recv(1024) #客户端和服务端的连接成功后,socket生成,紧接着在这里调用recv()方法,程序继续阻塞,直到客户端调用send方法,conn.recv(1024) 中的1024指的是一次最大接收1024个字节。print(str(client_data,'utf8'))conn.send(bytes("不要回答,不要回答",'utf8')) #服务端发送即对socket套接字进行写操作。conn.close()
socket_clinet.py
import socket
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.connect(ip_port)
sk.sendall(bytes("请求占领地球",'utf8'))
server_reply = sk.recv(1024)
print(str(server_reply,'utf8'))
sk.close()
基本的socket用法,很简单就实现了。那么我们深入一些:
1.能不能让客户端和服务端进行通信呢?
2.这是一个客户端,连接这个服务端。当多个客户端连接这个服务端会怎样?(这个测试下来,这种基本的socket是不能多个客户端访问的。)
那么我们来尝试解决问题1.
socket_server02.py
#!/usr/bin/env python3.5
#__author__:'ted.zhou'
'''
socket学习
'''
import socket
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)while True:print('server waiting ......')conn,addr = sk.accept()client_data = conn.recv(1024)print(str(client_data,'utf8'))conn.send(bytes("不要回答,不要回答",'utf8'))while True:client_data = conn.recv(1024)print(str(client_data,'utf8'))server_response = input(">>>")conn.send(bytes(server_response,'utf8'))conn.close()
socket_clinet02.py
#!/usr/bin/env python3.5
#__author__:'ted.zhou'
import socket
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.connect(ip_port)sk.sendall(bytes("请求占领地球",'utf8'))server_reply = sk.recv(1024)
print(str(server_reply,'utf8'))
while True:user_input = input(">>>:").strip()sk.send(bytes(user_input,'utf8'))server_reply = sk.recv(1024)print(str(server_reply,'utf8'))
sk.close()
先执行socket_server02.py
在执行socket_client02.py,执行结果如下:
socket_client02.py
不要回答,不要回答 #接到服务器的第一个响应
>>>:dd #客户端输入dd
你大爷 #哟,服务端骂人
>>>:龟孙 #骂回去
日你先人 #服务器又骂回来一句
>>>:socket_server02.py
server waiting ......
请求占领地球 #接到的第一个clinet send
dd #服务端收到dd
>>>你大爷 #服务端回复,d d看不懂,就说了句“你大爷”
龟孙 #乖乖,敢回嘴,我可是服务器
>>>日你先人 #接着骂
那么我这上面都是正常通信,输入的字符串都是正常的,假如客户端不输入了,直接退出。会怎样?
这里就不赘述老师的试验过程了,最终结果,老师说当clinet客户端停掉,windows和Linux的服务端对这个异常处理的方式不一样
但我自己在mac和Linux下尝试的结果一样,判断接收到clinet_data数据是否为空,为空就跳出循环。
#!/usr/bin/env python3.5
#__author__:'ted.zhou'
'''
socket学习
'''
import socket
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)while True:print('server waiting ......')conn,addr = sk.accept()client_data = conn.recv(1024)print(str(client_data,'utf8'))conn.send(bytes("不要回答,不要回答",'utf8'))while True:client_data = conn.recv(1024)if not client_data:break #判断当,对方传过来的值为空时,直接退出print('client_data',str(client_data,'utf8'))server_response = input(">>>")conn.send(bytes(server_response,'utf8'))conn.close()
windows下,当客户端停掉,server端 conn.recv(1024)得到的数据不是空值,而是异常,异常发生后,程序就会退出,所以这里就要用到异常处理方法try语法,具体代码如下:这段代码如果用到Linux中,将无限循环下去,因为客户端停掉后,服务端会认为conn.recv(1024)得到空值,这样无限循环下去。
#!/usr/bin/env python3.5
#__author__:'ted.zhou'
'''
socket学习
'''
import socket
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)
while True:
print('server waiting ......')
conn,addr = sk.accept()
client_data = conn.recv(1024)
print(str(client_data,'utf8'))
conn.send(bytes("不要回答,不要回答",'utf8'))
while True:
try:
client_data = conn.recv(1024)
print('client_data',str(client_data,'utf8'))
except Exception:
print("clinet closed,break")
break
server_response = input(">>>")
conn.send(bytes(server_response,'utf8'))
conn.close()
使用socket写一个远程的ssh工具:
04socket_server.py代码如下:
#!/usr/bin/env python3.5
#__author__:'ted.zhou'
'''
socket学习,做成可以远程输入命令,客户端获得输出结果,如果你的命令输出结果很多,那么客户端得到的结
'''
import socket
import subprocess
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)while True:print('server waiting ......')conn,addr = sk.accept()# client_data = conn.recv(1024)# print(str(client_data,'utf8'))# conn.send(bytes("不要回答,不要回答",'utf8'))while True:print("客户端{}已经连接,等待客户端传输命令... ...".format(conn.getpeername()))client_cmd_re = conn.recv(1024)if not client_cmd_re:break # 判断当,对方传过来的值为空时,直接退出(在客户端我已经判断用户输入不能为空,所以这里为空,只有一种可能,就是客户端关闭程序了.如果没有这句的break,会导致客户端一旦关闭,服务端也跟着关闭.# 因为当客户端关闭后,传过来的不知道是什么东西)print("用户传来了命令:%s"%client_cmd_re) # 打印输出用户传来的命令cmd_re_str = str(client_cmd_re,'utf8') # 将用户传来的命令转换成str# 将命令执行,并获得执行结果cmd_exec_result = subprocess.Popen(cmd_re_str,shell=True,stdout=subprocess.PIPE).stdout.read()# print(cmd_exec_result) # 打印执行的结果# print(len(cmd_exec_result)) # 打印结果的长度if len(cmd_exec_result) == 0 : # 判断结果是不是为空,为空说明用户传过来的命令,本服务器无法执行.cmd_exec_result = bytes("命令 '{}' 后没有返回执行结果,请检查命令是否正确...".format(cmd_re_str),'utf8') # 提示命令不对#将执行结果发送给客户端
conn.send(cmd_exec_result)conn.close()
04socket_client.py代码如下:
#!/usr/bin/env python3.5
#__author__:'ted.zhou'
import socket
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.connect(ip_port)# sk.sendall(bytes("请求占领地球",'utf8'))
#
# server_reply = sk.recv(1024)
# print(str(server_reply,'utf8'))
while True:input_cmd = input("cmd:").strip() # 用户输入命令if input_cmd == 'q':break # 用户如果输入的是q,退出输入命令的循环if not input_cmd:continue # 用户如果直接按了回车,既为空,则进行下次循环print(input_cmd) # 打印此次用户输入的命令sk.send(bytes(input_cmd,'utf8')) # 将用户的命令通过socket发送给服务器端cmd_exec_data = sk.recv(1024) # 接收服务器执行命令后返回的结果print(str(cmd_exec_data,'utf8'))
sk.close()
上面的代码已经实现了,client连接到server后,进行基本的简单的命令。却不能进行实时的交互,比如top,cd 这种执行后没法返回的命令。具体如何时间,第七天的课程暂不说明。
那么问题来了,client端在接收设置中用到了sk.recv(1024),设置了每次最大收1024个字节,当你执行一个ifconfig命令,字节将大于1024,客户端就会一次收不完,这些数据,会怎样。这些数据已经被服务端通过socket发送过来了。你再次调用sk.recv(1024)时,继续接收余下的数据。那么怎样才能继续接收呢?目前的代码是循环到下次输入命令时会接收ifconfig命令结果的后续。那它这次的命令就又要排队到后面了。
那么如何进行循环接收呢?当然是在本次执行命令中,在sk.recv(1024)代码前加while 循环。
问题又来了。默认是死循环,while True,那么本次命令循环接收sk.recv(1024)结束条件怎么设置呢。
先说明:这里处理方法只有一种,就是在服务端传给客户端字符串前,先把传输的字节数告诉客户端。客户端循环接收字节,并把接收到的字节数累加统计,然后拿接收到的字节总数和服务端发来的做比较。如果小于继续循环。
但是: 老师给我们理清了思路,尝试了3种测试的方法,通过这3次尝试,让我们渐渐的了解socket传输的内部原理。
尝试方案1:
客户端在接收调用sk.recv(1024)方法,我们可以尝试调大这个数值,看看结果。是可以,每次多收一些,但是,如果你一个字符串有100*1024bytes,你不能把接收数值调整到100M吧,那内存还不爆掉。并且socket官方建议最大不能超过8192,所以此方案不可行。并且一般设置500即可。
尝试方案2:
我们在接收哪里直接while True,一直接收,直到接收不到数据时就退出break
06socket_server.py 不需要改动
06socket_client.py 代码如下:
#!/usr/bin/env python3.5
#__author__:'ted.zhou'
'''
当服务端发送过来的字符串字节数过大,一次接收不完,客户端通过判断服务器端是不是发送完,来作为循环接收的依据。
'''
import socket
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.connect(ip_port)# sk.sendall(bytes("请求占领地球",'utf8'))
#
# server_reply = sk.recv(1024)
# print(str(server_reply,'utf8'))
while True:input_cmd = input("cmd:").strip() # 用户输入命令if input_cmd == 'q':break # 用户如果输入的是q,退出输入命令的循环if not input_cmd:continue # 用户如果直接按了回车,既为空,则进行下次循环print(input_cmd) # 打印此次用户输入的命令sk.send(bytes(input_cmd,'utf8')) # 将用户的命令通过socket发送给服务器端
res = bytes('','utf8')while True:cmd_exec_data = sk.recv(500) # 接收服务器执行命令后返回的结果res += cmd_exec_dataif not cmd_exec_data : #这里判断,当接收不到数据时,就退出循环breakprint(str(res,'utf8'))
sk.close()
ps:此方式不可行。原因是cmd_exec_data = sk.recv(500) 这里在接收完本次命令执行的所有结果后,会一直阻塞在这里。不会退出循环,此时客户端就卡死了。
总结:sk.recv()和sk.send()都会阻塞
尝试方案3:
在客户端判断服务端的数据是不是传完了,如果没传完,则继续循环接收。
05scoket_server.py 不需要改动
05socket_client.py 代码如下:
#!/usr/bin/env python3.5
#__author__:'ted.zhou'
'''
当服务端发送过来的字符串字节数过大,一次接收不完,客户端通过判断服务器端是不是发送完,来作为循环接收的依据.
如何判断服务器端是不是发送完成?
我们认为,客户端每次接收的最大值500字节.那么如果最后一次传过来的数据长度没有500字节,那么我们是不是就可以说这次就是最后一次传输来.
所以while 循环中判断接收到的数据长度小于500,就退出循环接收.
代码如下:
'''
import socket
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.connect(ip_port)# sk.sendall(bytes("请求占领地球",'utf8'))
#
# server_reply = sk.recv(1024)
# print(str(server_reply,'utf8'))
while True:input_cmd = input("cmd:").strip() # 用户输入命令if input_cmd == 'q':break # 用户如果输入的是q,退出输入命令的循环if not input_cmd:continue # 用户如果直接按了回车,既为空,则进行下次循环print(input_cmd) # 打印此次用户输入的命令sk.send(bytes(input_cmd,'utf8')) # 将用户的命令通过socket发送给服务器端
res &#61; bytes(&#39;&#39;,&#39;utf8&#39;)while True:cmd_exec_data &#61; sk.recv(500) # 接收服务器执行命令后返回的结果res &#43;&#61; cmd_exec_dataif len(cmd_exec_data) <500: &#xff03;当接收到的字节小于500就判断已经接收完了。breakprint(str(res,&#39;utf8&#39;))
sk.close()
这里我们执行命令&#xff0c;得到一些数据量还没有那么大的字符串时没有问题&#xff0c;担当字符串相当大时&#xff0c;就出现之前的那种错误了&#xff0c;原因是我们最初认为的客户端每次都是按最大500字节接收&#xff08;这个观点错了&#xff09;。两个因素导致单次接收可能没有500字节。
因素1&#xff0c;服务端发送会因为网络状态发送数据。如果网络不稳定&#xff0c;传个10几个bytes也是可能的。
因素2&#xff0c;客户端接收也可能因为网络或者性能&#xff0c;导致这次接收延迟了几百毫秒&#xff08;内部缓冲机制时间限制也许只有100毫秒&#xff09;。从而导致本次接收不到500字节。
总结&#xff1a;客户端不是每次接收都是按照最大限额的字节接收的。这样我们的代码&#xff1a;
while True:cmd_exec_data &#61; sk.recv(500) # 接收服务器执行命令后返回的结果res &#43;&#61; cmd_exec_dataif len(cmd_exec_data) <500: &#xff03;这里就会在没接收完时&#xff0c;就退出了本次命令执行结果接收呢。break
最终答案来了&#xff0c;代码如下&#xff1a;
07socket_server.py
#!/usr/bin/env python3.5
#__author__:&#39;ted.zhou&#39;
&#39;&#39;&#39;
socket学习,做成可以远程输入命令,客户端获得输出结果,如果你的命令输出结果很多,那么客户端得到的结
&#39;&#39;&#39;
import socket
import subprocess
ip_port &#61; (&#39;127.0.0.1&#39;,9999)
sk &#61; socket.socket()
sk.bind(ip_port)
sk.listen(5)while True:print(&#39;server waiting ......&#39;)conn,addr &#61; sk.accept()# client_data &#61; conn.recv(1024)# print(str(client_data,&#39;utf8&#39;))# conn.send(bytes("不要回答,不要回答",&#39;utf8&#39;))while True:print("客户端{}已经连接,等待客户端传输命令... ...".format(conn.getpeername()))client_cmd_re &#61; conn.recv(1024)if not client_cmd_re:break # 判断当,对方传过来的值为空时,直接退出(在客户端我已经判断用户输入不能为空,所以这里为空,只有一种可能,就是客户端关闭程序了.如果没有这句的break,会导致客户端一旦关闭,服务端也跟着关闭.# 因为当客户端关闭后,传过来的不知道是什么东西)print("用户传来了命令:%s"%client_cmd_re) # 打印输出用户传来的命令cmd_re_str &#61; str(client_cmd_re,&#39;utf8&#39;) # 将用户传来的命令转换成str# 将命令执行,并获得执行结果cmd_exec_result &#61; subprocess.Popen(cmd_re_str,shell&#61;True,stdout&#61;subprocess.PIPE).stdout.read()if len(cmd_exec_result) &#61;&#61; 0 : # 判断结果是不是为空,为空说明用户传过来的命令,本服务器无法执行.cmd_exec_result &#61; bytes("命令 &#39;{}&#39; 后没有返回执行结果,请检查命令是否正确...".format(cmd_re_str),&#39;utf8&#39;) # 提示命令不对
result_size &#61; len(cmd_exec_result) # 计算本次获得到结果是多少字节conn.send(bytes("CMD_RESULT_SIZE|{}".format(result_size),&#39;utf8&#39;)) # 首先将本次将要发送的字符串的大小告诉客户端.
conn.send(cmd_exec_result) #紧接着把执行结果发过去conn.close()
07socket_client.py
#!/usr/bin/env python3.5
#__author__:&#39;ted.zhou&#39;
&#39;&#39;&#39;
当服务端发送过来的字符串字节数过大,一次接收不完,客户端通过判断服务器端是不是发送完,来作为循环接收的依据.
如何判断服务器端是不是发送完成?
根据服务器端发来的大小,判断是否接收完成.
代码如下:
&#39;&#39;&#39;
import socket
ip_port &#61; (&#39;127.0.0.1&#39;,9999)
sk &#61; socket.socket()
sk.connect(ip_port)# sk.sendall(bytes("请求占领地球",&#39;utf8&#39;))
#
# server_reply &#61; sk.recv(1024)
# print(str(server_reply,&#39;utf8&#39;))
while True:input_cmd &#61; input("cmd:").strip() # 用户输入命令if input_cmd &#61;&#61; &#39;q&#39;:break # 用户如果输入的是q,退出输入命令的循环if not input_cmd:continue # 用户如果直接按了回车,既为空,则进行下次循环print(input_cmd) # 打印此次用户输入的命令sk.send(bytes(input_cmd,&#39;utf8&#39;)) # 将用户的命令通过socket发送给服务器端
server_ack_msg &#61; sk.recv(100)cmd_res_msg &#61; str(server_ack_msg,&#39;utf8&#39;).split(&#39;|&#39;)# "CMD_RESULT_SIZE|{}".format(result_size),&#39;utf8&#39;)# print(cmd_res_msg)if cmd_res_msg[0] &#61;&#61; "CMD_RESULT_SIZE": # 判断你发来的这个是不是文件大小的标示cmd_res_size &#61; int(cmd_res_msg[1]) #如果是,把大小付给cmd_res_size变量
res &#61; bytes(&#39;&#39;,&#39;utf8&#39;)recevied_size &#61; 0 # 初始化字符串大小为0while recevied_size
sk.close()
到此为止&#xff0c;我们认为&#xff0c;socket接收大数据的功能已经实现。大功告成&#xff5e;&#xff5e;&#xff5e;&#xff0c;no&#xff0c;还有错误&#xff0c;当数据量大时&#xff0c;会出现 “socket编程中最大的一个坑 粘包 ”
我们看07socket_server.py中最后发送的代码
conn.send(bytes("CMD_RESULT_SIZE|{}".format(result_size),&#39;utf8&#39;)) # 首先将本次将要发送的字符串的大小告诉客户端. conn.send(cmd_exec_result)
我们看到一连两次发送。这就会出现“socket编程中最大的一个坑 粘包 ”&#xff0c;原因是缓冲区的问题&#xff0c;你两次发送&#xff0c;缓冲区会把两次要发送的内容放到一起发送。
那么怎么解决呢&#xff1f;
两个方案&#xff1a;
1.在两次发送之间sleep(1) 间隔1秒&#xff0c;这样缓冲区就失效。但是这种方式low,如果并发大就会很慢。
2.发送完文件大小后&#xff0c;使用conn.recv(100)这个能阻塞的方法&#xff0c;获取客户端返回来已经接收到文件大小信息的确认信息。&#xff08;当然客户端也要加返回给服务端的确认信息。&#xff09;
最终代码如下&#xff1a;
08socket_server.py
#!/usr/bin/env python3.5
#__author__:&#39;ted.zhou&#39;
&#39;&#39;&#39;
socket学习,做成可以远程输入命令,客户端获得输出结果,如果你的命令输出结果很多,那么客户端得到的结
&#39;&#39;&#39;
import socket
import subprocess
ip_port &#61; (&#39;127.0.0.1&#39;,9999)
sk &#61; socket.socket()
sk.bind(ip_port)
sk.listen(5)while True:print(&#39;server waiting ......&#39;)conn,addr &#61; sk.accept()# client_data &#61; conn.recv(1024)# print(str(client_data,&#39;utf8&#39;))# conn.send(bytes("不要回答,不要回答",&#39;utf8&#39;))while True:print("客户端{}已经连接,等待客户端传输命令... ...".format(conn.getpeername()))client_cmd_re &#61; conn.recv(1024)if not client_cmd_re:break # 判断当,对方传过来的值为空时,直接退出(在客户端我已经判断用户输入不能为空,所以这里为空,只有一种可能,就是客户端关闭程序了.如果没有这句的break,会导致客户端一旦关闭,服务端也跟着关闭.# 因为当客户端关闭后,传过来的不知道是什么东西)print("用户传来了命令:%s"%client_cmd_re) # 打印输出用户传来的命令cmd_re_str &#61; str(client_cmd_re,&#39;utf8&#39;) # 将用户传来的命令转换成str# 将命令执行,并获得执行结果cmd_exec_result &#61; subprocess.Popen(cmd_re_str,shell&#61;True,stdout&#61;subprocess.PIPE).stdout.read()if len(cmd_exec_result) &#61;&#61; 0 : # 判断结果是不是为空,为空说明用户传过来的命令,本服务器无法执行.cmd_exec_result &#61; bytes("命令 &#39;{}&#39; 后没有返回执行结果,请检查命令是否正确...".format(cmd_re_str),&#39;utf8&#39;) # 提示命令不对
result_size &#61; len(cmd_exec_result) # 计算本次获得到结果是多少字节conn.send(bytes("CMD_RESULT_SIZE|{}".format(result_size),&#39;utf8&#39;)) # 首先将本次将要发送的字符串的大小告诉客户端.client_ack &#61; conn.recv(50)if str(client_ack,&#39;utf8&#39;) &#61;&#61; "CLIENT_READY_TO_RECV":conn.send(cmd_exec_result)conn.close()
08socket_client.py
#!/usr/bin/env python3.5
#__author__:&#39;ted.zhou&#39;
&#39;&#39;&#39;
当服务端发送过来的字符串字节数过大,一次接收不完,客户端通过判断服务器端是不是发送完,来作为循环接收的依据.
如何判断服务器端是不是发送完成?
根据服务器端发来的大小,判断是否接收完成.
代码如下:
&#39;&#39;&#39;
import socket
ip_port &#61; (&#39;127.0.0.1&#39;,9999)
sk &#61; socket.socket()
sk.connect(ip_port)# sk.sendall(bytes("请求占领地球",&#39;utf8&#39;))
#
# server_reply &#61; sk.recv(1024)
# print(str(server_reply,&#39;utf8&#39;))
while True:input_cmd &#61; input("cmd:").strip() # 用户输入命令if input_cmd &#61;&#61; &#39;q&#39;:break # 用户如果输入的是q,退出输入命令的循环if not input_cmd:continue # 用户如果直接按了回车,既为空,则进行下次循环print(input_cmd) # 打印此次用户输入的命令sk.send(bytes(input_cmd,&#39;utf8&#39;)) # 将用户的命令通过socket发送给服务器端
server_ack_msg &#61; sk.recv(100)cmd_res_msg &#61; str(server_ack_msg,&#39;utf8&#39;).split(&#39;|&#39;)# "CMD_RESULT_SIZE|{}".format(result_size),&#39;utf8&#39;)# print(cmd_res_msg)if cmd_res_msg[0] &#61;&#61; "CMD_RESULT_SIZE": # 判断你发来的这个是不是文件大小的标示cmd_res_size &#61; int(cmd_res_msg[1]) #如果是,把大小付给cmd_res_size变量sk.send(b"CLIENT_READY_TO_RECV")res &#61; bytes(&#39;&#39;,&#39;utf8&#39;)recevied_size &#61; 0 # 初始化字符串大小为0while recevied_size
sk.close()