C#Socket.Receive()SocketException:由于套接字未连接,因此不允许发送或接收数据的请求

时间:2015-07-29 22:55:42

标签: c# sockets windows-services socketexception

我正在使用Windows 8.1中的C#,。Net 4.5进行Windows Socket编程。

所以,我做了一个非常简单的操作。我正在实现一个客户端 - 服务器类型系统,所有这些都在本地机器上运行,通过套接字进行通信。服务器是Windows服务,客户端是用户应用程序。

该服务根据客户端的请求执行一些OCR计算,然后将结果返回给请求进程。该服务具有一个侦听套接字,可以随时接受传入请求,创建一个新套接字并用于响应每个请求。新请求套接字的端口号在请求中指定。这样做是为了允许侦听套接字处理并发请求。

服务的监听套接字工作正常。我能够从连接到侦听套接字的用户应用程序接收请求。当角色颠倒时会出现问题:服务需要连接到客户端拥有的Socket,并通过客户端拥有的套接字发送OCR结果。让我们进入代码:

服务器端

this.LocalAddress = Dns.GetHostEntry("localhost").AddressList[0]; // localhost ip addr

...
//*************** Receive request
//*************** Perform computation
...

// respond to requester with results from OCR 
using (Socket responder = new Socket(this.LocalAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
{
    IPEndPoint requestEndpoint = new IPEndPoint(this.LocalAddress, request.portNum);
    responder.Connect(requestEndpoint); //same endpoint as client

    if(failure)
        responder.Send(Encoding.UTF8.GetBytes(this.OCRFailureMessage));
    else
        responder.Send(Encoding.UTF8.GetBytes(ocrResults.ToString()));
}

不会抛出任何异常,服务会继续,好像一切都成功。

客户端

//localhost address
IPAddress address = Dns.GetHostEntry("localhost").AddressList[0]; // localhost ip addr

// endpoint to listen on for response from StartOCRService
IPEndPoint myEndpoint = new IPEndPoint(address, 50002);

// create socket to receive response on and bind to listening endpoint
Socket receiver = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
receiver.Bind(myEndpoint);
receiver.Listen(10);

...
//************ Connect to service listening socket
//************ Send OCR request to service (myEndpoint port# included)
...

// accept connection from service
receiver.Accept();

// receive data from service
byte[] returnData = new byte[1024];
int numBytesReceived = receiver.Receive(returnData); //EXCEPTION THROWN

receiver.Receive()调用的客户端抛出异常。以下是例外情况:

  

类型:SocketException

     

消息:不允许发送或接收数据的请求,因为套接字未连接(使用sendto调用在数据报套接字上发送时)没有提供地址。

     

ErrorCode:10057(套接字未连接)

所以,我挂断的地方是客户端的套接字没有连接。行receiver.Accept()是一个阻塞调用,等待服务器调用responder.Connect()。同时单步执行双方,我看到客户端等待receiver.Accept(),直到服务器调用responder.Connect()。我认为这意味着客户端套接字已接受连接。任何人都可以发现客户端套接字保持未连接状态并抛出此异常的原因吗?

非常感谢所有帮助,谢谢!

编辑:2015年7月29日5:07p

其他一些可能有用的细节。服务调用后responder.Connect() responder.Connected为 true 和responder.RemoteEndpoint是客户端正在侦听的端点(地址和端口#已确认)。

然而,对于客户来说同样不能说。在receiver.Accept()调用传递receiver.Connected为 false 之后,receiver.RemoteEndpoint抛出与上面相同的异常。

进一步深入接收者的成员我发现receiver.DontFragment抛出了一个带有消息的System.NotSupportedException

  

不支持此协议版本。

我正在使用的协议出了什么问题?我全面使用TCP。也许它与地址族有关?

2 个答案:

答案 0 :(得分:1)

TCP服务器侦听套接字用于接受连接,不用于与TCP客户端对等方的后续数据交换。 accept()为连接的每个对等客户端返回另一个唯一的客户端<>服务器套接字。

一种非常常见的模式是一台服务器向许多客户端提供请求/响应服务。由accept()返回的客户端<>服务器套接字可以被传送到专用于该客户端的线程或进程,该线程或进程读取,解析,处理其客户端请求并在同一客户端服务器套接字上发送回复。或者,select / epoll异步设计可以在一个线程/进程中处理请求/响应。

每个客户端一个线程/进程需要为每个客户端堆栈(坏),但允许简单的“内联”代码,(好)。

异步select / epoll只需要一个堆栈,(好),但通常需要一个用户空间状态机来处理事件,(坏)。

选择你的毒药:)

在请求进入后关闭客户端<>服务器套接字,然后尝试在另一个方向打开连接以提供回复,这种情况更为常见。这需要两个服务器和客户端都很混乱。

答案 1 :(得分:0)

所以@Martin James对我的设计缺陷给予了极大的帮助。在通过现有套接字连接发出请求后,没有理由建立新的套接字连接。抛出的例外是在设计旁边,无论它有多糟糕。此行接受客户端代码中的连接

// accept connection from service
receiver.Accept();

需要

// accept connection from service
Socket handler = receiver.Accept();

然后使用handler接收邮件。返回的套接字对象已正确连接。

再次感谢@Martin James