python socket传输大文件的方法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wshk918/article/details/91403730

×××××××××××××方法一:

	发送端
1、计算发送文件大小,然后结合文件的其他信息,组成文件头先发送一次。
2、发送文件数据时用sendall(),一次发送所有数据(好像是重复调用了send())
	接收端
1、接收端根据接受文件的大小和recv_size计算要接收数据的次数,
2、然后把每次接收的数据连在一起
3、因为可能不是整除,最后要判断下最后一次具体接收多少字节数据(感觉也可以不用这样,直接接收)

1、计算文件大小

1、os.path.getsize(filepath)
2、os.stat(filepath).st_size

2、socket接收数据的操作的注意事项

因为下面的原因,我们要在接收端接收头文件时做一些处理,用来与数据文件区分

#服务器
import socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(("127.0.0.1",8000))
server.listen(3)
while True:
    sock,adddr = server.accept()
    data = sock.recv(1024)
    print(data.decode("utf8")+"\n")
    if(data.decode("utf8") == "111"):
        print("dsfaf")
        server.close()
sock.close()
#客户端
import socket 
import json
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(("127.0.0.1",8000))
header_data = {
    'file_size': 1000299,
}
client.send(json.dumps(header_data).encode("utf-8"))
client.send("ripo".encode("utf8"))
client.send("fasdf".encode("utf8"))
client.send("oiposfdpakf".encode("utf8"))
client.send("111".encode("utf8"))
client.close()

服务器输出结果

{"file_size": 1000299}ripofasdfoiposfdpakf111

可见虽然客户端是用多个send函数发送的,服务器采用1024大小的缓冲(sock.recv(1024))区,一次把所有数据的都接收了。这样就不能区分出我们先发送的文件头了。

解决方案

一:使用send和recv隔离

在发送端自一次发送数据,也就是发送文件头信息的时候,接收端在接收后在给发送端发送一个数据,
然后在接收端接收(不必处理),相当于在发送文件头信息和文件信息之间加了一步,这样接收端就能区
分开了。

二(推荐):使用struct计算头文件大小

使用struct库
1、首先在发送端和接收端约定一个fmt,也就是头文件的格式。
2、客户端 
	struct.pack(fmt,v1,v2.....)
3、服务器端
(1)struct.calcsize(fmt),可以计算大小,这样就可以在接收端接收指定大小的数据。这个大小对应头
文件数据的大小。
(2)struct.unpack(fmt,v1,v2.....)

第一种方法的代码:

#服务器端
import socket
import struct
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(("127.0.0.1",3008))
server.listen(3)
while True:
    print("start.......")
    sock,adddr = server.accept()
    d = sock.recv(struct.calcsize("l"))
    total_size = struct.unpack("l",d)
    num  = total_size[0]//1024
    data = b''
    for i in range(num):
        data += sock.recv(1024)
    data += sock.recv(total_size[0]%1024)

    with open("11.png","wb") as f:
        f.write(data)
    sock.close()
sock.close()
#客户端
import socket 
import struct
import os
import json
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(("127.0.0.1",3008))
print("connect success....")
filepath = "1.png"
size =  os.stat(filepath).st_size
f= struct.pack("l",os.stat(filepath).st_size)
client.send(f)
img = open(filepath,"rb")
client.sendall(img.read())
img.close()
client.close()

××××××××××××方法二:

方法二:
	发送端(事先知道接收的缓冲区大小buf)
1、读取要发送的文件,获取总大小
2、每次发送buf大小的数据,是的接收端正好接这么多
3、一直发,直到把文件的数据发送完
	接收端
1、一直接收知道数据的不大于0

第二种方法的代码:

#服务器
import socket
import struct
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(("127.0.0.1",3008))
server.listen(3)
while True:
    print("start......")
    sock,adddr = server.accept()
    total_data = b''
    num = 0
    data = sock.recv(1024)
    total_data += data
    num =len(data)
    # 如果没有数据了,读出来的data长度为0,len(data)==0
    while len(data)>0:
        data = sock.recv(1024)
        num +=len(data)
        total_data += data       
    with open("11.png","wb") as f:
        f.write(total_data)
    sock.close()
sock.close()
#客户端
import socket 
import struct
import os
import json

client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(("127.0.0.1",3008))
print("connect success.....")
filepath = "1.png"
img = open(filepath,"rb")
# print(len(img.read()))

client.sendall(img.read())
img.close()
client.close()

使用python socket分发大文件

python socket编程(传输字符、文件、图片)

struct.pack()、struct.unpack()和struct.calcsize()

socket中AF_*** 和socket.SOCK_STREAM的资料来自《python核心编程》
套接字是计算机网络数据结构,它体现了上节中所描述的“通信端点”的概念。在任何
类型的通信开始之前,网络应用程序必须创建套接字。可以将它们比作电话插孔,没有它将
无法进行通信。
套接字的起源可以追溯到 20 世纪 70 年代,它是加利福尼亚大学的伯克利版本 UNIX(称
为 BSD UNIX)的一部分。因此,有时你可能会听过将套接字称为伯克利套接字或 BSD 套接
字。套接字最初是为同一主机上的应用程序所创建,使得主机上运行的一个程序(又名一个
进程)与另一个运行的程序进行通信。这就是所谓的进程间通信(Inter Process Communication,
IPC)。有两种类型的套接字:基于文件的和面向网络的。
UNIX 套接字是我们所讲的套接字的第一个家族,并且拥有一个“家族名字” AF_UNIX
(又名 AF_LOCAL,在 POSIX1.g 标准中指定),它代表地址家族(address family): UNIX。
包括 Python 在内的大多数受欢迎的平台都使用术语地址家族及其缩写 AF;其他比较旧的系
统可能会将地址家族表示成域(domain)或协议家族(protocol family),并使用其缩写 PF 而
非 AF。类似地, AF_LOCAL(在 2000~2001 年标准化)将代替 AF_UNIX。然而,考虑到
后向兼容性,很多系统都同时使用二者,只是对同一个常数使用不同的别名。 Python 本身仍
然在使用 AF_UNIX。
因为两个进程运行在同一台计算机上,所以这些套接字都是基于文件的,这意味着文件
系统支持它们的底层基础结构。这是能够说得通的,因为文件系统是一个运行在同一主机上
的多个进程之间的共享常量。
第二种类型的套接字是基于网络的,它也有自己的家族名字 AF_INET,或者地址家族:
因特网。另一个地址家族 AF_INET6 用于第 6 版因特网协议(IPv6)寻址。此外,还有其他
的地址家族,这些要么是专业的、过时的、很少使用的,要么是仍未实现的。在所有的地址
家族之中,目前 AF_INET 是使用得最广泛的。
Python 2.5 中引入了对特殊类型的 Linux 套接字的支持。套接字的 AF_NETLINK 家族(无
连接[见 2.3.3 节])允许使用标准的 BSD 套接字接口进行用户级别和内核级别代码之间的 IPC。
之前那种解决方案比较麻烦,而这个解决方案可以看作一种比前一种更加优雅且风险更低的
解决方案,例如,添加新系统调用、 /proc 支持,或者对一个操作系统的“IOCTL”。
针对 Linux 的另一种特性(Python 2.6 中新增)就是支持透明的进程间通信(TIPC)协
议。 TIPC 允许计算机集群之中的机器相互通信,而无须使用基于 IP 的寻址方式。 Python 对
TIPC 的支持以 AF_TIPC 家族的方式呈现。
总的来说, Python 只支持 AF_UNIX、 AF_NETLINK、 AF_TIPC 和 AF_INET 家族。因为
本章重点讨论网络编程,所以在本章剩余的大部分内容中,我们将使用 AF_INET。
展开阅读全文

socket文件传输丢失数据

10-17

最近刚接触socket编程,使用TCP协议,阻塞式的socket点对点传输文件。当服务器和客户端都运行在一台电脑上,多大的文件都没问题(我最大试过700多兆的),但是把客户端放到另一个电脑上运行时,稍微大一点的文件只能传5K左右,也没有任何异常,求高手帮忙解答一下,问题可能出在哪里rn[color=#FF0000]服务器端程序:[/color]rnvoid CPPServerDlg::OnBtnsendfile() rnrn // TODO: Add your control notification handler code herern UpdateData(true);rn CFile myFile;rn if(!myFile.Open(m_filename, CFile::modeRead | CFile::typeBinary))rn rn AfxMessageBox("文件不存在!",MB_OK|MB_ICONERROR);rn return;rn rn SOCKET_STREAM_FILE_INFO StreamFileInfo;rn WIN32_FIND_DATA FindFileData; //记载当前文件的基本信息rn FindClose(FindFirstFile(m_filename,&FindFileData)); //把文件信息放在了FindFileDatarn memset(&StreamFileInfo,0,sizeof(SOCKET_STREAM_FILE_INFO));rn strcpy(StreamFileInfo.szFileTitle,myFile.GetFileTitle());rn StreamFileInfo.dwFileAttributes = FindFileData.dwFileAttributes;rn StreamFileInfo.ftCreationTime = FindFileData.ftCreationTime;rn StreamFileInfo.ftLastAccessTime = FindFileData.ftLastAccessTime;rn StreamFileInfo.ftLastWriteTime = FindFileData.ftLastWriteTime;rn StreamFileInfo.nFileSizeHigh = FindFileData.nFileSizeHigh;rn StreamFileInfo.nFileSizeLow = FindFileData.nFileSizeLow;rn //发送文件基本信息rn send(g_hAcceptSocket,(const char *)&StreamFileInfo,sizeof(SOCKET_STREAM_FILE_INFO),0);rn UINT dwRead=0;rn UINT dw=0;rn byte* data = new byte[1024];rn int ret=0;rn rn while(true)rn rn dw=myFile.Read(data,1024);rn if (dw<1024)rn rn if ((send(g_hAcceptSocket,(char*)data,dw,0))==SOCKET_ERROR)rn rn AfxMessageBox("发送文件失败!");rn rn break;rn rn ret=send(g_hAcceptSocket,(const char*)data,1024,0);rn if (ret==0)rn rn break;rn rn if (ret==SOCKET_ERROR)rn rn break;rn rn rn rn myFile.Close();rn delete []data;rn AfxMessageBox("发送完毕!");rnrnrn[color=#FF0000]客户端程序:[/color]rnrn UINT dwRecv = 0;rn byte* data = new byte[1024];rn while(TRUE)rn rn memset(data,0,1024);rn dwRecv=recv(m_hSocket,(char*)data,1024,0);rn if (dwRecv<1024)rn rn destFile.Write(data,dwRecv);rn break;rn rn if (dwRecv==0)rn rn break;rn rn else if (dwRecv==SOCKET_ERROR)rn rn break;rn rn destFile.Write(data,dwRecv);rn rn SetFileTime((HANDLE)destFile.m_hFile,&StreamFileInfo.ftCreationTime,rn &StreamFileInfo.ftLastAccessTime,&StreamFileInfo.ftLastWriteTime);rn destFile.Close();rn delete []data;rn SetFileAttributes(StreamFileInfo.szFileTitle,StreamFileInfo.dwFileAttributes);rn closesocket(m_hSocket);rn AfxMessageBox("接收完毕!");rnrn连接部分的代码省略 论坛

没有更多推荐了,返回首页