我想异步发送文件。我继续发送文件客户端->服务器->另一个客户端,但是如果我要发送很大的文件,则在文件完全发送之前,客户端无法向服务器发送任何其他命令。对于每个客户端要发送的文件,我创建一个新线程,在该线程中,我将一次读取1kb的文件并发送到服务器,然后服务器将接收到1kb的文件,然后进一步发送给所需的客户端。问题是,当客户端发送文件时,套接字中已充满了来自服务器的字节。我应该为每个要发送的文件创建一个客户端服务器套接字?我已经尝试了一切,但没有成功。
答案 0 :(得分:2)
为每次传输创建专用套接字是一种解决方案,除非同时连接的数量很大(系统上只有这么多IP端口可用,而服务器将需要两倍),否则这不是一个不好的解决方案。线程并没有像您想象的那样简化,而是引入了自己的挑战。 select
是从单个线程/进程在多个套接字上有效传输数据的更简单方法。它通过公开底层操作系统对哪些套接字已准备好读取和写入程序的知识而起作用。
无论采用哪种线程选择,采用多路套接字方法给您带来的挑战是服务器必须告知收件人为每次新传输打开一个新的连接回服务器。现在,您需要一个命令mechansim来告诉收件人打开下一个文件的新连接。
另一种选择是仅打开一个套接字,但同时通过该套接字发送多个文件。您可以通过发送包含每个文件的下一部分的数据结构来实现此目的,而不是直接流式传输文件。例如,您可能发送的消息看起来像这样(为清晰起见,以JSON呈现,但这将是有效的传输格式):
[
{
"name": "file.txt",
"bytes": "some smallish chunk of content",
"eof": false
},
{
"name": "another.txt",
"bytes": "chunk of another.txt content",
"eof": true
}
]
这个例子当然是天真地简单化了,但希望足以使您理解:通过构造您要发送的消息,您可以描述哪些文件,哪些字节块属于哪个文件,然后发送多个字节块。文件一次。由于采用了client-> server-> client方法,这似乎是通往我的最佳途径。
答案 1 :(得分:0)
使用类似于以下内容的结构
struct transferPacket
{
unsigned packetOfFile; // = 0 when starting a new file
unsigned fileNumber; // incremented with each new file
unsigned byteCount;
char payload[ MAX_PAYLOAD_LEN ];
};
当packetOfFile == 0时,则启动一个新文件,并且有效载荷包含文件名 否则,指示正在传输文件的哪一部分。
当byteCount = 0时,则该文件号的EOF
以上仅需一个TCP套接字
可以一次传输多个文件。 接收方知道数据包属于哪个文件以及有效载荷位于文件的哪个位置。
除了文件的第一个数据包和EOF数据包或文件的最后一个数据包之外,发送方每次都发送相同数量的字节