尝试使用Socket接收文件

时间:2014-02-01 01:48:12

标签: c# sockets filestream

我正在尝试通过套接字传输文件,并在收到文件时将其写入文件(以便可以在其他应用程序中打开)。它主要工作,除了接近结尾(我猜)它阻塞,因为它试图读取整个8 KB的块,当没有那么多的东西接收。我不知道如何解决这个问题。我知道我应该接收的总字节数,如果有帮助的话。谢谢!

using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) {
  socket.Connect(e.IPAddress, e.Port);
  using (var fs = new FileStream(e.Filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read)) {
    byte[] buffer = new byte[8192];
    int read;
    while ((read = socket.Receive(buffer)) > 0) {
      fs.Write(buffer, 0, read);
    }
  }
}

1 个答案:

答案 0 :(得分:-1)

From the MSDN...

  

如果没有可用于读取的数据,则接收方法将阻塞,直到数据可用,除非使用Socket.ReceiveTimeout设置超时值。如果超出超时值,则Receive调用将抛出SocketException。如果您处于非阻塞模式,并且协议堆栈缓冲区中没有可用数据,则Receive方法将立即完成并抛出SocketException。您可以使用Available属性来确定数据是否可供读取。当Available为非零时,重试接收操作。

Socket.Receive()方法阻止,因为即使没有更多可用数据,连接仍在另一端打开。有几种方法可以解决这个问题,一种方法需要事先知道文件的大小,一旦读取了很多字节就停止另一种方法。另一种方法是使用非阻塞套接字(通过将Socket.Blocking属性设置为false)并从Socket.Available属性获取数据。后者在编写代码时需要更多的技巧,因为读取操作不会再停止代码。

如果您事先知道数据的大小,可以将其与目前已阅读的数量进行比较,并在达到该数量后停止:

//If you know the size beforehand, set it as an int and compare
// it to what you have so far
int totalBytes = 9001;

using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
    socket.Connect(e.IPAddress, e.Port);
    using (var fs = new FileStream(e.Filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read))
    {
        byte[] buffer = new byte[8192];
        int read;
        int bytesSoFar = 0; //Use this to keep track of how many bytes have been read

        do
        {
            read = socket.Receive(buffer);
            fs.Write(buffer, 0, read);
            bytesSoFar += read;

        } while (bytesSoFar < totalBytes);
    }
}

请记住,第二个示例不是很强大,在尝试使用同一个套接字发送多个文件时无法正常工作。但是对于一个简单的1文件传输,这应该可以正常工作。