使用C#进行套接字编程

时间:2009-01-12 17:21:10

标签: c# sockets

我正在构建一个客户端/服务器应用程序来定期备份某些文件。基本上,客户端将监视某些文件以进行更改,并将它们上载到服务器。然后服务器将接收它们并使用递增的后缀保存它们(即“filename_v1”,“filename_v2”等。现在,我设法完成了大部分工作,但是出现了一些问题,我找不到与它们相关的任何内容。

在开始之前,请注意:

  • 我尽力找到自己的解决方案。
  • 我跟踪(并完成了)几个套接字编程教程。
  • 我不认识任何有c#和/或socket编程经验的人。

这是逻辑:

  1. 服务器启动,开始监听。 (BeginAccept)
  2. 当客户端连接时,会创建一个“worker”套接字。
  3. 工作套接字开始接收。 (BeginReceive)/客户端发送文件(SendFile)
  4. 收到数据时,会保存文件。 (也检查早期版本,但这里无关紧要。)
  5. 转到3.(我们需要从同一个客户端接收更多文件。)
  6. 步骤1-4工作正常。

    问题出现了:在第5步中,即使服务器什么都没有收到,也会调用onDataReceive(回调方法),服务器会发现自己处于无限循环中。我试图关闭(或断开)工作插座,但没有机会。我开始怀疑我的算法可能有点草率。

    无论如何,我们非常感谢任何评论,建议或帮助。

3 个答案:

答案 0 :(得分:2)

你的回调是否实现了EndReceive?

你是否正在传递状态对象?如果是,请将其中一个属性作为传递给BeginReceive的缓冲区,然后在回调中检查状态缓冲区以查看是否收到了任何数据。如果没有,请不要继续循环。

struct SocketStateObject
{
  public byte[] Buffer;
  public Socket Socket;
}



Socket mySocket = new Socket(...);
SocketStateObject state;
state.Buffer = new byte[1024];
state.Socket = mySocket;

socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, callback, state);

//don't remember the signature
public void callback(IAsyncResult a)
{
  if (((SocketStateObject)a.State).Buffer.Length = 0)
    //don't call socket.beginreceive again.
}

答案 1 :(得分:1)

我在过去一年左右用于在.NET中传输医学图像的套接字库上做了一些工作。在早期,我们很难检测到套接字何时关闭,但最终达到了稳定的解决方案。

我们的应用程序使用NetworkStream来读取/写入套接字。我们有一个与您类似的线程,它是在新连接到达时创建的,用于读取和写入网络数据。我们调用下面的方法来轮询数据何时到达或连接何时关闭。如果您不想轮询,可以调整该方法以使用更长的超时。当我们知道数据可用时,我们从NetworkStream对象中读取。

下面的关键点是套接字上的零字节发送,这似乎检测到套接字何时关闭,如评论中所述。只是调用OnNetworkError方法来启动正在关闭的线程。

史蒂夫


protected override bool NetworkHasData() 
{
    if (_socket == null)
        return false;

    // Tells the state of the connection as of the last activity on the socket
    if (!_socket.Connected)
    {
        OnNetworkError(null, true);
        return false;
    }

    // This is the recommended way to determine if a socket is still active, make a
    // zero byte send call, and see if an exception is thrown.  See the Socket.Connected
    // MSDN documentation.  Only do the check when we know there's no data available
    try
    {
        List readSockets = new List();
        readSockets.Add(_socket);
        Socket.Select(readSockets, null, null, 100000);
        if (readSockets.Count == 1)
        {
            if (_socket.Available > 0)
                return true;
            OnNetworkError(null, true);
            return false;
        }

        _socket.Send(new byte[1], 0, 0);
    }
    catch (SocketException e)
    {
        // 10035 == WSAEWOULDBLOCK
        if (!e.NativeErrorCode.Equals(10035))
            OnNetworkError(e, true);
    }

    return false;
}

答案 2 :(得分:1)

我认为你应该看看WCF。当您可以使用可以轻松通过线路传输字节数组的消息传递应用程序时,为什么要使用套接字编程重新发明轮子?

WCF将处理您当前正在尝试执行的安全性,数据传输和所有管道。当然,要传输文件,您将被迫将消息大小设置为高于默认值...但我会认真考虑在重新编码轮子之前使用WCF制作原型。

我建议使用以下资源: