废话不多说,上代码,具体逻辑分析详见注释,本次目的是解决上一个案例中出现的,超出recv(num)设置的值时,信息包会不完整,并与下一个client请求的信息包粘在一块,也就是俗称的粘包问题。

Server端代码:
#!/usr/bin/env python
#   --coding = utf-8
#   Author Allen Lee
import socket,subprocess,socketserver

ip_port = ('10.12.4.82',8088,)
server = socket.socket()
server.bind(ip_port)
server.listen(0)
while True:
    conn,addr = server.accept()
    print(addr)
    while True:
        try:
            res_data = conn.recv(1024)
            if len(res_data) == 0 :break
            ret = subprocess.Popen(str(res_data,encoding='utf-8'),shell=True,stdout=subprocess.PIPE)
            res_msg = ret.stdout.read()
            if len(res_msg) == 0:
                send_data = 'cmd_err'
            else:
                send_data = str(res_msg,encoding='gbk')
            print(send_data, type(send_data))
            #通知客户端,本次包的总大小,并打上‘ready’的signal,让client来抓取,注意这里用“|”为分隔符
            send_tag = 'ready|%d' %(len(res_msg))
            conn.send(bytes(send_tag,encoding='utf-8'))
            #为了调试代码进度所添加的输出
            print(send_tag)
            #cilent在收到‘ready’的标签后,给服务端回一个‘start’,通知服务端可以发包
            recv_data = conn.recv(1024)
            recv_tag = str(recv_data,encoding='utf-8')
            #在服务端接收到来时client的确认信息之后,则开始发送client请求的信息;
            if recv_tag == 'start':
                conn.send(bytes(send_data,encoding='utf-8'))
            else:
                conn.send(bytes('do not receive the start signal',encoding='utf-8'))
        except Exception:
            break

    conn.close()

client端代码:
#!/usr/bin/env python
#   --coding = utf-8
#   Author Allen Lee
import socket
server_port = ('10.12.4.82',8088,)
client = socket.socket()
client.connect(server_port)

while True:
    send_data = input('>>: ').strip()
    if len(send_data) == 0:continue
    if send_data == 'exit':break
    send_msg = bytes(send_data,encoding='utf-8')
    client.send(send_msg)
    res_data = client.recv(1024)
    res_tag = str(res_data,encoding='utf-8')
    #client接收并解析服务端发回的信息是否是ready开头的,以此判断是否要开始发包了
    if res_tag.startswith('ready'):
        #将ready后的数字传给res_total,用于之后的信息回显,同理也可以来做一个进度条的显示功能
        res_total = int(res_tag.split('|')[1])
        #初始化当前接收的信息节点数值
        res_now = 0
        # cilent在收到‘ready’的标签后,给服务端回一个‘start’,通知服务端可以发包
        client.send(bytes('start',encoding='utf-8'))
        #在当前信息值不大于总值的情况下,循环获取并打印服务端发过来的信息
        while res_now <= res_total:
            #设置recv最小接收信息单元 的字节数
            res_data = client.recv(1024)
            res_now += len(res_data)
            print('total:%s----now:%s'%(res_total,res_now))
            print(str(res_data,encoding='utf-8'))

client.close()

解决了粘包的问题,就可以进一步实现scp的功能了,这里需要大家理解一个情况:
所有的图片、文件、视频、音频 等,其实底层传输都是通过二进制(0101)的编码,因此我们完全可以将 全文件类型 解码为bytes类型,然后逐行以读取file的形式将信息发去client端,client端再进行拼接,最后以原有的‘文件名+后缀名’命名。
详细实现情况请见本系列下一篇,关于scp的实现代码

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐