我有一个带有服务器和客户端的 C# 项目,使用
TcpListener
和 TcpClient
,我想让客户端向服务器发送文件。
我是网络新手,但据我所知,最好的方法是让客户端首先将文件的大小发送到服务器,这样它就可以准备接收正确的字节数,然后客户端发送文件,服务器不是一次性接收文件,而是分块接收。
我有这个代码:
客户:
byte[] fileNameByte = Encoding.UTF8.GetBytes(fileName);
byte[] fileNameLen = BitConverter.GetBytes(fileNameByte.Length);
byte[] fileData = File.ReadAllBytes(fileName);
byte[] clientData = new byte[4 + fileNameByte.Length + fileData.Length];
fileNameLen.CopyTo(clientData, 0);
fileNameByte.CopyTo(clientData, 4);
fileData.CopyTo(clientData, 4 + fileNameByte.Length);
StreamCommands.Write(clientData, 0, clientData.Length);
服务器:
byte[] fileData = new byte[999999999];
int recievedBytesLen = await Task.Run(() => currentClient.StreamCommands.Read(fileData, 0, fileData.Length));
int fileNameLen = BitConverter.ToInt32(fileData, 0);
string fileName = Encoding.UTF8.GetString(fileData, 4, fileNameLen);
int st = fileName.LastIndexOf("\\") + 1;
int en = fileName.Length;
string fname = fileName.Substring(st, en - st);
BinaryWriter bWrite = new BinaryWriter(File.Open(recievedFilePath+fname, FileMode.Create));
bWrite.Write(fileData, 4 + fileNameLen, recievedBytesLen - 4 - fileNameLen);
bWrite.Close();
这段代码确实有效,我可以一次发送一个小文件,但我不想仅限于小文件,而且我知道以块的形式接收数据会更有效,所以我想知道我会怎么做关于在我的代码中实现它。
我强烈建议您使用更高级别的网络堆栈;例如,您可以嵌入 ASP.NET Core 服务器,然后使用标准 HTTP 文件上传。
如果您确实需要 TCP/IP,那么您需要重新审视您的协议,然后开始使用循环。目前的协议发送文件名的长度,然后发送文件名,然后发送文件数据。缺少的是文件数据的长度;您应该发送文件名的长度、文件名、文件数据的长度和文件数据。
然后,在接收端,需要从套接字连接中重复读取字节,直到有足够的文件名长度,然后为文件名分配空间,然后重复读取字节,直到有整个文件名,然后重复读取字节,直到有足够的文件数据长度,然后为文件数据分配空间,然后重复读取字节,直到拥有整个文件数据。
或者,您可以为整个消息使用单个长度前缀,但您仍然需要字段的长度前缀来区分文件名和文件数据。
我的博客上有一些代码可以为每条消息添加前缀。