博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python利用socket传输文件
阅读量:4964 次
发布时间:2019-06-12

本文共 5790 字,大约阅读时间需要 19 分钟。

今日单词

socket 插座 套接字 少开的phone 手机server 服务器 少我bind 捆绑client客户 可来嗯accept 接受  阿婆晒的addr connconnect 接受recv 接收send 发送decode解码encode编码total 全部的 偷偷size 大小 塞子result  结果 内稍ciipconfig 微软操作系统中的一个系统命令,用于查看本机的IP信息ipconfig/all查看当前电脑网卡的ip信息、DNS信息、DHCP服务器信息等import subprocess  子过程可以执行远端命令import struct结构 是不的 将该模块可以把一个类型,如数字,转成固定长度的bytespack包装 怕可unpack 打开包裹

粘包现象

须知:只有TCP有粘包现象,UDP永远不会粘包粘包不一定会发生如果发生了:1.可能是在客户端已经粘了      2.客户端没有粘,可能是在服务端粘了

socket收发消息的原理

img

所谓粘包问题主要还是因为接收方不知道消息之间的界限 还有系统缓存区的问题 时间差的原因,不知道一次性提取多少字节的数据所造成的。

为什么要有缓存区

输入输出缓冲区的默认大小一般都是 8K,可以通过 getsockopt() 函数获取:1024字节=1k

缓冲区的作用?

存储少量数据

如果你的网络出现短暂的异常或者波动,接收数据就会出现短暂的中断,影响你的下载或者上传的效率.

但是 凡是都是双刃剑,缓冲区解决了上传下载的传输效率的问题,带来了黏包问题.

6.收发的本质:

不一定是一收一发

为什么出现粘包?

1,接收方没有及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包) recv会产生黏包(如果recv接受的数据量(1024)小于发送的数据量,第一次只能接收规定的数据量1024,第二次接收剩余的数据量)

2,发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据也很小,会合到一起,产生粘包)send 也可能发生粘包现象.(连续send少量的数据发到输出缓冲区,由于缓冲区的机制,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络)

总结精简版

第一种.连续短暂的send多次(数据量很少),你的数据会统一发送出去,(不可控)第二种: send的数据过大,大于对方recv的上限时,对方第次recv时,会接收上一次没有recv完的剩余的

如何解决粘包现象

错误实例:

1. 可以扩大recv的上限. recv(10240000000000000000000000000) 不是解决这个问题的根本原因, 8g, 10G,这些都会直接放在内存中.2. 故意延长recv的时间. sleep 这样会非常影响效率.

low版解决粘包现象

server

# 原因# 1. 粘包第一种: send的数据过大,大于对方recv的上限时,对方第二次recv时,会接收上一次没有recv完的剩余的数据。# 解决方式 服务端 发送时记录字节长度 在将不固定第字节长度 利用模块转化为固定4个长度bytes# 先发送4个字节过去 在发送原内容# 客户端 先接受固定4个字节 在利用固定的4个字节bytes利用模块转回原来的字节个数(int)# 利用while循环接收# 利用的模块# import struct# # 将一个数字转化成等长度的bytes类型。# ret = struct.pack('i', 180000000)# # print(ret, type(ret), len(ret))## # 通过unpack反解回来# ret1 = struct.unpack('i',ret)[0]# # print(ret1)# print(ret1, type(ret1))# import struct# import subprocess# obj = subprocess.Popen('dir1',#                        shell=True,#                        stdout=subprocess.PIPE,#                        stderr=subprocess.PIPE,#                        )# print(obj.stdout.read().decode('gbk'))  # 正确命令# print(obj.stderr.read().decode('gbk'))  # 错误命令import structimport subprocessimport socketphone=socket.socket()phone.bind(('127.0.0.1',6666))phone.listen(5)while 1:    coon, addr = phone.accept()    while 1:        try:            from_client_data=coon.recv(1024)            print(f'来自{addr}消息{from_client_data.decode("utf-8")}')            obj = subprocess.Popen(from_client_data.decode('utf-8'),                                   shell=True,                                   stdout=subprocess.PIPE,                                   stderr=subprocess.PIPE,                                   )            to_client_data=(obj.stderr.read().decode('gbk')+obj.stdout.read().decode('gbk')).encode('utf-8')#总字节数            total_size=len(to_client_data)#总字节数长度            # print(total_size)            # 将一个数字转化成等长度的bytes类型。            size = struct.pack('i', total_size)            coon.send(size)#发送固定4个字节            coon.send(to_client_data)#发送总数据        except Exception:            break    coon.close()phone.close()

client

import socketimport structphone=socket.socket()phone.connect(('127.0.0.1',6666))while 1:    to_cerver_data=input('????')    if not to_cerver_data:        # 服务端如果接受到了空的内容,服务端就会一直阻塞中,所以无论哪一端发送内容时,都不能为空发送        print('发送内容不能为空')        continue    phone.send(to_cerver_data.encode('utf-8'))    from_server_size=phone.recv(4)#接收固定4个字节    from_server_total= struct.unpack('i',from_server_size)[0] # 反解报头    tatal=b''    while len(tatal)

旗舰版

优点

1.高大上版:自定制报头

2.高大上版:可以解决文件过大的问题.

server端

import socketimport structimport json# 1. 创建socket对象(买手机) 左边是 右边是# phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone = socket.socket() # 可以默认不写# 连接服务器ip地址与端口 左边服务器IP地址 右边端口phone.connect(('127.0.0.1', 9999))# 发消息while 1:    try:        to_server = input('>>>').strip()        if to_server.upper() == 'Q':            phone.send('q'.encode('utf-8'))#发消息            break        phone.send(to_server.encode('utf-8'))#send 发送        # 第1步 先读前4个 此时读的是字典长度        head_4 = phone.recv(4)        #第2步 将固定4个byres 转化为字典byes原长度数字 此时是数字类型        ret1 = struct.unpack('i',head_4)[0]        ##第3步 读取 字典长度byres        head_dic_len = phone.recv(ret1)        #第4步将字典 byres解码 转化为 特殊的字符串        head_dic_json=head_dic_len.decode('utf-8')        #第5步将 json转化为字典        head_dic=json.loads(head_dic_json)        #第6步获取 字典有用的信息 比如文件byres 长度        place_len=head_dic['file_size']        #第7步读取 原文件        place = phone.recv(place_len)        print(place.decode('utf-8'))    except ConnectionResetError:        print('对方服务器崩了。。。。')        break# 关机phone.close()#关闭手机#ipconfig

client端

import socket#建立通讯import subpr1111ocess#远程返回import struct#将该模块可以把一个类型,如数字,转成固定长度的bytesimport jsonphone = socket.socket()#买手机phone.bind(('127.0.0.1', 9999))#插卡phone.listen(5)#开放监听# 4. 接收连接print('start')conn, addr = phone.accept()while 1:    try:        cmd = conn.recv(1024) #  接收发送端的消息        obj = subprocess.Popen(cmd.decode('utf-8'),                               shell=True,                               stdout=subprocess.PIPE,#正确命令                               stderr=subprocess.PIPE,#错误命令                               )        #返回数据  由于有黏包现象 客户端接收不了这么多        result = obj.stdout.read() + obj.stderr.read()#gbk 格式        result = result.decode('gbk').encode('utf-8')#解码成utf-8        #第一步制作报头 head 头        head_dict={'file_size':len(result)}        #第2步将字典转为json字符串        head_dict_json = json.dumps(head_dict)        #第3步 将json字符串 转为 byes类型        head_dict_byres=head_dict_json.encode('utf-8')        #第4步将json的byres 长度转为固定4个 byres        total_size_byres=struct.pack('i',len(head_dict_byres))        #第5步 发送 固定4个byres total_size_byres        conn.send(total_size_byres)        #第6步 发送字典byres 给客服端        conn.send(head_dict_byres)        # 第7步 发送原内容 给客服端        conn.send(result)    except ConnectionResetError:        breakconn.close()phone.close()

转载于:https://www.cnblogs.com/saoqiang/p/11377235.html

你可能感兴趣的文章
(笔记)Linux内核学习(一)之内核介绍
查看>>
angular双向数据绑定
查看>>
ioc控制反转
查看>>
算法与数据结构 (四) 排序 一 交换类排序
查看>>
Windows Server 2012 虚拟化实战:网络(二)
查看>>
TCP与UDP的区别
查看>>
PHP循环while do while循环
查看>>
如何设置linux启动过程中的停止阶段
查看>>
Codeforces Round #246 (Div. 2)
查看>>
进程管理之基本概念
查看>>
nginx mac
查看>>
【转-整理】Spring的Ioc理解,写的很通俗易懂
查看>>
第一篇
查看>>
[USACO13JAN] Cow Lineup (单调队列,尺取法)
查看>>
jeasyui 中文网
查看>>
mktime()函数使用
查看>>
P1342 请柬
查看>>
P2764 最小路径覆盖问题(网络流24题之一)
查看>>
bzoj1066 [SCOI2007]蜥蜴
查看>>
1.1_Python 简介
查看>>