【问题标题】:How to send files over tcp with TcpListener/Client? SocketException problem如何使用 TcpListener/Client 通过 tcp 发送文件? Socket异常问题
【发布时间】:2009-06-18 15:18:07
【问题描述】:

我正在开发一个简单的应用程序,使用 TCPListener 和 TCPClient 类通过 TCP 发送文件。这是发送文件的代码。

Stop 是一个 volatile 布尔值,有助于随时停止进程,并且 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。我猜这与在读取所有数据之前关闭远程套接字有关,但是正确的方法是什么?我应该什么时候关闭发送客户端?

我在 google 上没有找到任何好的文件传输示例,而我发现的示例与我正在做的事情有类似的实现,所以我想我遗漏了一些东西。

编辑:我收到此错误“无法从传输连接读取数据”。这是一个 IOException,其内部异常是一个 SocketException。

我已经在 sender 函数中添加了这个,但我仍然得到同样的错误,代码永远不会到达 stream.close(),当然 tcpclient 永远不会真正关闭......所以我现在完全迷路了。

buffer = new byte[1];
client.Client.Receive(buffer);
stream.Close();

【问题讨论】:

  • 实际上应用程序既是客户端又是服务器。目前我正在从应用程序转移到自身,所以是的,客户端是发送者。

标签: c# .net file tcp


【解决方案1】:

通常您希望在套接字上设置 LINGER 选项。在 C++ 下这将是 SO_LINGER,但在 Windows 下这实际上并没有按预期工作。你真的想这样做:

  • 完成发送数据。
  • 在 how 参数设置为 1 的情况下调用 shutdown()。
  • 在 recv() 上循环,直到它返回 0。
  • 调用closesocket()。

取自:http://tangentsoft.net/wskfaq/newbie.html#howclose

C# sharp 可能已在其库中纠正了这一点,但我对此表示怀疑,因为它们是建立在 winsock API 之上的。

编辑:

更详细地查看您的代码。我看到你根本没有发送任何标题,所以在接收端你不知道你实际上应该读取多少字节。知道要读取的套接字的字节数使得这个问题更容易调试。请记住,如果您没有正确关闭它,关闭套接字仍然可以截断最后一点数据。

另外让你的缓冲区大小是可变的不是线程安全的,真的不会给你带来任何好处。使用 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()

【讨论】:

  • LingerState 不起作用,我已经尝试过... :( 我将尝试其余的建议...
  • 有头信息正在发送,为了问题篇幅,我把它拿出来了。还有一些错误处理。停止工作,因为我真的不在乎在退出循环之前是否循环 3 或 4 次,它允许主线程向执行线程发出信号以停止发送或接收。
猜你喜欢
  • 2017-01-27
  • 1970-01-01
  • 2013-05-12
  • 1970-01-01
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
  • 1970-01-01
  • 2021-10-28
相关资源
最近更新 更多