热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python2.0s12day7

开发的第二阶段网络编程阶段之所以叫网络编程,是因为,这里面就不是你在一台机器中玩了.多台机器,CS架构.即客户端和服务器端通过网络进行通信的编程了.首先想实现网络的通信,你得先学网

开发的第二阶段 网络编程阶段
之所以叫网络编程,是因为,这里面就不是你在一台机器中玩了.多台机器,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 # 如果已接收的字符串大小小于服务器传过来的大小,则循环接收data &#61; sk.recv(50) # 接收数据recevied_size &#43;&#61; len(data) # 将数据累加res &#43;&#61; data # 累加统计已接收的数据print(str(res,&#39;utf8&#39;)) # 打印最终结果
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 # 如果已接收的字符串大小小于服务器传过来的大小,则循环接收data &#61; sk.recv(50) # 接收数据recevied_size &#43;&#61; len(data) # 将数据累加res &#43;&#61; data # 累加统计已接收的数据print(str(res,&#39;utf8&#39;)) # 打印最终结果
sk.close()

 



推荐阅读
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • centos安装Mysql的方法及步骤详解
    本文介绍了centos安装Mysql的两种方式:rpm方式和绿色方式安装,详细介绍了安装所需的软件包以及安装过程中的注意事项,包括检查是否安装成功的方法。通过本文,读者可以了解到在centos系统上如何正确安装Mysql。 ... [详细]
  • 负载均衡 LVS vs Nginx 对比
    前言今天总结一下负载均衡中LVS与Nginx的区别,之前看过好几篇博文一开始就说LVS是单向的,Nginx是双向的,我个人认为这是不准确的,LVS三种模式中,虽然DR模式以及TU ... [详细]
  • 初学MVC架构时可能会觉得MVC其实是多余的,因为它平白无故的增加了页面联系的复杂度但是当你只用JSP,不用MVC写一个项目的时候,你才会发觉MVC是多么有趣和有用,因为它大大的减低了文件的复 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 解决VS写C#项目导入MySQL数据源报错“You have a usable connection already”问题的正确方法
    本文介绍了在VS写C#项目导入MySQL数据源时出现报错“You have a usable connection already”的问题,并给出了正确的解决方法。详细描述了问题的出现情况和报错信息,并提供了解决该问题的步骤和注意事项。 ... [详细]
  • 开发笔记:计网局域网:NAT 是如何工作的?
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了计网-局域网:NAT是如何工作的?相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 众筹商城与传统商城的区别及php众筹网站的程序源码
    本文介绍了众筹商城与传统商城的区别,包括所售产品和玩法不同以及运营方式不同。同时还提到了php众筹网站的程序源码和方维众筹的安装和环境问题。 ... [详细]
  • MongoDB用户验证auth的权限设置及角色说明
    本文介绍了MongoDB用户验证auth的权限设置,包括readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase、cluster相关的权限以及root权限等角色的说明和使用方法。 ... [详细]
  • 简介RSocket是在华盛顿特区举行的SpringOne平台会议上宣布的,是一种新的第7层语言无关的应用网络协议。它是一种基于ReactiveStreams背压的双 ... [详细]
  • SmartMesh WireLess HART 资料总结
    SmartMeshWireLessHART资料总结--刘振君2017.01.0923:00:00IEEE802.15是一个工作组98年成立,专门从事 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有