C# “非阻塞UDP套接字.NET”;“无法立即完成非阻塞套接字操作”;例外

C# “非阻塞UDP套接字.NET”;“无法立即完成非阻塞套接字操作”;例外,c#,.net,exception,udp,udpclient,C#,.net,Exception,Udp,Udpclient,我用C#编写了一个小的UDP客户机-服务器类,用于在Linux和Windows机器之间提供通信 < > Windows中C语言中的UDP客户端和服务器的实现是我最初为Linux编写的C++代码的直接改写。 我在Linux机器之间的运行时没有问题,但Linux和Windows链接之间偶尔会出现间歇性问题 由于应用程序,我需要快速、无阻塞的UDP套接字操作 由于一个客户机是Linux,所以C#下的代码必须使用一些编组的魔力 代码如下: public bool Connect(string s

我用C#编写了一个小的UDP客户机-服务器类,用于在Linux和Windows机器之间提供通信

< > Windows中C语言中的UDP客户端和服务器的实现是我最初为Linux编写的C++代码的直接改写。 我在Linux机器之间的运行时没有问题,但Linux和Windows链接之间偶尔会出现间歇性问题

由于应用程序,我需要快速、无阻塞的UDP套接字操作

由于一个客户机是Linux,所以C#下的代码必须使用一些编组的魔力

代码如下:

    public bool Connect(string sIPAddr, int portNumber)
    {
        try
        {
            if (portNumber > 65535 && portNumber < 0)
            {
                this._isReady = false;
                return this._isReady;
            }

            this._ipPort = portNumber;
            this._ipAddress = IPAddress.Parse(sIPAddr);
            IPEndPoint ipep = new IPEndPoint(this._ipAddress, this._ipPort);
            this._myUDPClient = new Socket(ipep.Address.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
            this._myUDPClient.Blocking = false;
            this._myUDPClient.Connect(this._ipAddress, this._ipPort);

            this._isReady = true;
            return this._isReady;
        }
        catch (Exception)
        {
            this._isReady = false;
            return this._isReady;
        }
    }
我希望能够理解这个问题,以及为什么会出现这个问题,以及如何解决它,因为我从想法中获得了乐趣


谢谢

您正在将从中读取消息的套接字设置为非阻塞。如果操作无法立即完成,则指示套接字不阻塞。实际上,这意味着如果您试图从套接字读取数据,而没有任何内容等待读取,那么调用将不会成功返回

我不知道如何调用
MessageReceived
,但是我假设无论调用什么,它都不会在调用之前检查信息是否已准备好从套接字读取

当您遇到间歇性问题时,这表明在大多数情况下,当调用
MessageReceived
时,有数据要从套接字读取

如果你想继续使用非阻塞IO,你需要改变你的逻辑,让它捕捉IO异常并在短时间延迟后重试(如果你确定那里会有数据),或者在尝试执行读取之前检查是否有数据可从套接字读取

检查套接字上是否有可用信息(在尝试读取之前)的一种方法是使用socket.Poll。比如:

if (_myUDPClient.Poll(myTimeoutInMicroSeconds, SelectMode.SelectRead)){
       // Try to read the new messsage
} else {
    continue;  // go back to top of loop and try again
}

您可能还需要检查
SelectError
状态,以确定套接字是否出现故障。我的大部分套接字编程都是C++的,所以我对.NET的细节不太确定。

< p>我没有回答这个问题,但我需要指出一些非常重要的事情:

    catch (Exception)
    {
        this._isReady = false;
        return this._isReady;
    }
不要隐藏这样的异常。当某件事失败时,你将永远没有机会尝试去修复它,因为你永远不会知道为什么某件事失败。请务必使用适当的异常处理

由于应用程序,我需要快速、无阻塞的UDP套接字操作

这种说法是不正确的。非阻塞套接字并不更快,它们只是在操作完成之前返回


我确实建议您切换回阻塞套接字,因为您似乎是套接字编程的新手。首先让应用程序运行,然后尝试对其进行优化。

将阻塞标志设置为false,会告诉套接字如果数据不存在,请不要阻塞,在这种情况下,您会收到错误。如果阻塞标志为true,则调用只会阻塞,直到收到信息,然后从调用返回。您需要做一些其他的事情,然后稍后再试。MessageReceived是如何触发/调用的?我修改了原始帖子以包括MessageReceived是如何调用的。实际上,这是一个超时的while循环。在我的while循环中,只要计时器还没有过期,我就不断地检查。一旦消息成功接收,我指示代码清除缓冲区并准备好进行下一次接收。UDP保留消息边界,并自动进行分段和重新组装,直到可以阅读为止。在我的例子中,在网络中传输的UDP数据报也被设置为32字节。C++中我用PEEK检查数据现在读,我猜这里轮询做类似的事情。非常感谢@谢尔盖:遗憾的是,我倾向于同意杰戈芬的观点。非阻塞套接字虽然更有趣,可以让您用更少的线程管理更多的并发连接,但速度并不快。它们的管理也更复杂,所以除非你有理由,否则不应该真正使用它们。看看你的while循环,它实际上是在套接字上阻塞的,所以你没有从使用非阻塞套接字中得到明显的好处。你猜@Serge评论并删除了评论?非阻塞套接字不会更快。请随意做基准测试。每个客户端使用一个线程会降低性能。但不是直接的,在这种情况发生之前,您需要同时获得一组客户端(当这种情况发生时,我建议您切换到异步套接字方法,而不是非阻塞套接字)。但是,在您真正需要之前,不要做任何更复杂的事情。在不涉及太多细节的情况下,每个服务器只有一个客户机。Linux机器是一个硬实时系统,它从Windows UI机器接收命令并执行适当的任务。我同意你所说的非阻塞套接字,但是正如我所说的,我不太多的Windows代码,而不是非常熟悉.NET,因此我改写了我的C++套接字实现的实时环境。因此,我不能坐着无限期地等待一个阻塞套接字,我必须分配时间,如果它失败了,就跳过它。因此,非阻塞给了我更多的自由。所描述的问题是.NETThen在linux应用程序中切换到异步方法而不是非阻塞套接字,并在windows应用程序中坚持使用阻塞套接字。它强制您以某种方式编码,linux应用程序仍将响应,因为异步方法(
BeginReceive
/
EndReceive
)不会阻止。在Windows中将阻止设置为true只会挂起应用程序,而不会从中退出。我知道
if (_myUDPClient.Poll(myTimeoutInMicroSeconds, SelectMode.SelectRead)){
       // Try to read the new messsage
} else {
    continue;  // go back to top of loop and try again
}
    catch (Exception)
    {
        this._isReady = false;
        return this._isReady;
    }