c# - 如何使用 TcpListener/Client 通过 tcp 发送文件? SocketException问题

标签 c# .net file tcp

我正在开发一个简单的应用程序,使用 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/

相关文章:

c# - WPF 和 WinForms WebBrowser 控件之间存在哪些功能差异?

c# - 在 C# 中获取 Javascript Modified Dropdownlist 的选定值

c# - Func<T> 的性能和继承

java.lang.OutOfMemoryError : Direct buffer memory when invoking Files. 读取所有字节

c - C中获取字符串第一个元素的第一个元素

c# - 如何使用 Mono.ZeroConf 注册服务?

c# - Windows 应用商店应用程序 - 如何在搜索 super 按钮文本框中获取水印

c# - 将过程输出存储在数组中

.net - 为整个应用程序域定义文化

c++ - Qt C++ : Save project in file