我正在开发一个简单的应用程序,使用 TCPListener 和 TCPClient 类通过 TCP 发送文件。这是发送文件的代码。
Stop 是一个 volatile bool 值,它有助于随时停止进程,并且 WRITE_BUFFER_SIZE 可能会在运行时更改(另一个 volatile)
while (remaining > 0 && !stop)
{
DateTime current = DateTime.Now;
int bufferSize = WRITTE_BUFFER_SIZE;
buffer = new byte[bufferSize];
int readed = fileStream.Read(buffer, 0, bufferSize);
stream.Write(buffer, 0, readed);
stream.Flush();
remaining -= readed;
// Wait in order to guarantee send speed
TimeSpan difference = DateTime.Now.Subtract(current);
double seconds = (bufferSize / Speed);
int wait = (int)Math.Floor(seconds * 1000);
wait -= difference.Milliseconds;
if (wait > 10)
Thread.Sleep(wait);
}
stream.Close();
这是处理接收端的代码:
do
{
readed = stream.Read(buffer, 0, READ_BUFFER_SIZE);
// write to .part file and flush to disk
outputStream.Write(buffer, 0, readed);
outputStream.Flush();
offset += readed;
} while (!stop && readed > 0);
现在,当速度较低(大约 5KBps)时,一切正常,但是,随着速度的提高,接收器大小变得更容易在从流中读取时引发 SocketException。我猜这与在读取所有数据之前关闭远程套接字有关,但是正确的方法是什么?我应该什么时候关闭发送客户端?
我没有在谷歌上找到任何文件传输的好例子,而我发现的例子与我正在做的事情有类似的实现,所以我想我遗漏了什么。
编辑: 我收到此错误“无法从传输连接读取数据”。这是一个 IOException,其内部异常是 SocketException。
我已经在 sender 函数中添加了这个,但我仍然得到同样的错误,代码永远不会到达 stream.close() 并且当然 tcpclient 永远不会真正关闭......所以我现在完全迷路了。
buffer = new byte[1];
client.Client.Receive(buffer);
stream.Close();
最佳答案
通常你想在套接字上设置 LINGER 选项。在 C++ 下,这将是 SO_LINGER,但在 Windows 下,这实际上并没有按预期工作。你真的想这样做:
- 完成发送数据。
- 调用 shutdown() 并将 how 参数设置为 1。
- 循环 recv() 直到它返回 0。
- 调用closesocket()。
取自:http://tangentsoft.net/wskfaq/newbie.html#howclose
C# sharp 可能已经在它的库中纠正了这个问题,但我对此表示怀疑,因为它们是建立在 winsock API 之上的。
编辑:
更详细地查看您的代码。我看到您根本没有发送 header ,因此在接收方您不知道实际应该读取多少字节。知道要读取套接字的字节数会使这个问题更容易调试。请记住,如果您没有正确关闭套接字,关闭套接字仍然会截断最后一位数据。
此外,让您的缓冲区大小可变不是线程安全的,实际上不会给您带来任何好处。使用 stop 作为 volatile 是安全的,但不要指望它是即时的。换句话说,在获得停止的更新值之前,循环可能会运行几次。在多处理器机器上尤其如此。
Edit_02:
对于 TCPClientClass,您想执行以下操作(据我所知,目前无法访问 C#)。
// write all the bytes
// Then do the following
client.client.Shutdown(Shutdown.Send) // This assumes you have access to this protected member
while (stream.read(buffer, 0, READ_BUFFER_SIZE) != 0);
client.close()
关于c# - 如何使用 TcpListener/Client 通过 tcp 发送文件? SocketException问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1013294/