c# socket . receive () SocketException:由于套接字未连接,发送或接收数据的请求被拒
本文关键字:数据 请求 连接 receive socket SocketException 套接字 | 更新日期: 2023-09-27 18:05:22
我正在努力在Windows 8.1上使用c#, . net 4.5进行Windows Socket编程。
我在做一个非常简单的操作。我正在实现一个客户机-服务器类型的系统,全部在本地机器上运行,通过套接字进行通信。服务器是Windows服务,客户端是用户应用。
服务根据客户端的请求执行一些OCR计算,然后将结果返回给请求进程。服务有一个监听套接字,它在任何时候都接受传入的请求,一个新的套接字被创建并用于响应每个请求。新的响应套接字的端口号在请求中指定。这样做是为了允许监听套接字处理并发请求。
服务的监听套接字工作正常。我能够从连接到侦听套接字的用户应用程序接收请求。当角色互换时,问题就出现了:服务需要连接到客户端拥有的套接字,并通过客户端拥有的套接字发送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 (Socket is not connected)
所以,我挂机的地方是客户端的套接字没有连接。线路receiver.Accept()
是阻塞呼叫,等待服务器呼叫responder.Connect()
。同时遍历两边,我看到客户机等待receiver.Accept()
,直到服务器调用responder.Connect()
。我认为这意味着客户端套接字已经接受了连接。有人能指出客户端套接字保持未连接并且抛出此异常的原因吗?
所有的帮助是非常感激,非常感谢!
一些可能有用的附加细节。业务调用responder.Connect()
响应器后。Connected true和responder。RemoteEndpoint是客户端正在监听的端点(地址和端口号#已确认)。
receiver.Accept()
呼叫通过receiver后。连接false和接收者。RemoteEndpoint抛出了与上面相同的异常。
进一步挖掘receiver的成员,我发现了receiver。DontFragment抛出了一个系统。NotSupportedException与消息
不支持此协议版本
我使用的协议有问题吗?我正在全面使用TCP。也许这与地址家庭有关?
TCP服务器监听套接字用于接受连接,它不用于与TCP客户端对等体的后续数据交换。Accept()为每个连接的对等客户端返回另一个唯一的client<>服务器套接字。
一个非常常见的模式是一台服务器向许多客户机提供请求/响应服务。accept()返回的client<>server套接字可以通信到专用于该客户端的线程或进程,该线程或进程在同一个client<>server套接字上读取、解析、处理其客户端请求并发送应答。另外,select/epoll异步设计可以在一个线程/进程中处理请求/响应。
一个线程/进程每个客户端需要一个堆栈,(坏),但允许简单的'内联'代码,(好)。
异步select/epoll只需要一个堆栈(好的),但通常需要一个用户空间状态机来处理事件(坏的)。
选择你的毒药:)
在请求进入后关闭client<>服务器套接字,然后尝试在另一个方向打开连接以提供应答的情况要少见得多。这需要服务器和客户端同时存在,并且非常混乱。
所以@Martin James对我的设计缺陷帮助很大。在对现有套接字连接发出请求后,没有理由建立新的套接字连接。抛出的异常与设计无关,不管它有多糟糕。在我的客户端代码
中接受连接的这一行// accept connection from service
receiver.Accept();
必须是
// accept connection from service
Socket handler = receiver.Accept();
,然后使用handler
接收消息。返回的套接字对象已正确连接。