Socket not connected exception after calling EndAccept and accessing RemoteEndPoint - c#

When accessing the RemoteEndPoint property of an accepted socket on the server, a SocketException: 'The socket is not connected' is sometimes thrown.
This happens occasionally (like once in 100 connection attempts) and only when there is a significant latency over the network (e.g. 10ms+, wifi network). Seems to be some kind of race condition but I'm not sure what can be done to prevent this.
Server code:
this.Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.Socket.Bind(new IPEndPoint(IPAddress.Parse("0.0.0.0"), port));
this.Socket.Listen(0);
this.Socket.BeginAccept(OnSocketAccepted, null);
private void OnSocketAccepted(IAsyncResult ar)
{
var socket = Socket.EndAccept(ar);
var endPoint = socket.RemoteEndPoint; // SocketException: The socket is not connected
}
Client code:
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ip, port);
// times out after a couple of seconds if the exception happened on the server
Server is running on Mono 6.4.0.198 on ARMv7 rev4 Raspberry Pi 3b+
Client is running on Windows 10 .NET framework 4.6.1 console app
I thought EndAccept basically guaranteed that the socket would be in a connected state and the RemoteEndPoint would be set. I've gone through the whole msdn EndAccept and RemoteEndPoint documentation and can't find any obvious mistakes or misunderstandings.

The Socket can close after you have called EndAccept() and before you have queried RemoteEndPoint. It can also close before your callback calls EndAccept(), this will also throw a Socket Exception.
There a a number of race conditions that can happen in here, particularly if your system is slow. You can check Socket.Connected but even that isn't guaranteed.
The correct approach is a Try/Catch and gracefully exit or throw an unrecoverable socket.
e.g.,
catch (SocketException ex)
#region SocketException
{
/// Some SocketExceptions we manage quietly. Others we surface as critical errors.
if ((SocketError)ex.ErrorCode == SocketError.AddressAlreadyInUse)
{
Log.Error("Endpoint failed to start. IPEndPoint {ipEndPoint} already in use.", this.localIPEndPoint.ToString());
// Execution will continue after finally{}
}
else
{
Log.Error(ex, "Endpoint has ended with an unrecoverable socket error:", Name);
throw;
}
}

Related

Why disconnect a TCP socket in order to connect?

I'm working on a piece of code, where a connection is made to a TCP socket.
The code contains the following excerpt:
// Close the socket if it is still open
if (_socket != null)
{
Disconnect();
}
// Create the socket object
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
The DisConnect() method does (amongst other things):
var socket = _socket;
_socket = null;
socket.Close();
I don't understand the beginning: why disconnect in order to connect?
I have tried removing that part of the code, but then the whole thing became very unstable.
Does anybody have an idea?
Thanks
Once a TCP socket has been closed, it can't be reused, so a new socket is needed for a new TCP connection.
If you want to reuse the same socket for a new TCP connection after a disconnect, you need to use the Socket.Disconnect() method with the reuseSocket parameter set to true.

C# socket problems

I connected to PCs with a cable in an attempt to simulate server\client. Server starts listening at specific EndPoint and sometimes later a client connects. All went well and I settled on maximum speed of about 24 Mbps for one connection (port).
So now I reversed the roles and can't get connection Socket.BeginConnect(ServerEndPoint, new AsyncCallback(OnConnectCallback), _ClientSocket) times out and sets localEndpoint to 0.0.0.0
Here is the code for client:
public void ConnectToServer(IPAddress iPAddress, int Port)
{
connected.Reset();
IPEndPoint ServerEndPoint = new IPEndPoint(iPAddress, Port);
try
{
_ClientSocket = new Socket(iPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_ClientSocket.BeginConnect(ServerEndPoint, new AsyncCallback(OnConnectCallback), _ClientSocket);
connected.WaitOne();
// Here I would like to start async receiving but there's no connection
}
catch (SocketException)
{
// TODO:
}
}
private void OnConnectCallback(IAsyncResult result)
{
try
{
Socket client_StateSocket = (Socket)result.AsyncState;
client_StateSocket.EndConnect(result);
/// Here I get 0.0.0.0
connected.Set();
}
catch (SocketException)
{
// TODO:
}
}
The server is bascialy from MSDN example. It starts listening for incoming connections, goes in perpetual while cycle and sits waiting for Socket.BeginAccept to trigger (but it never does).
I suspected firewall, but the settings look the same on both PCs and works fine in reversed way, so what might be the problem?
When you do development of a Server/Client architecture, it is usually enough to have both run on the same machine and let them talk via the Loopback IP adress. As a general rule the networking code does not care if the other end is on the same computer, the same switch - or the Voyager 2 probe (well, they do care a little as the Latency is quite high).
If you are having issues in deployment/testing, then with 99% propability you are dealing with a Networking problem, not a programming one. Sometimes there will be some required changes (like exposing the option to set proxy settings). But debugging will be a Networking operation first.
My first guesses are towards firewalls (including the one built into Windows). And then things that work similar to a firewall, like NAT layers.

How can I gracefully start my C# TCP client before I start my TCP server

I am writing a fairly simple TCP/IP client application. I am able to successfully connect when I start the server (another seperate application) and then start the client in that order. I would like to make the client robust so that I can start it first and it doesnt break. Also I dont want a special user action to tell the client to try and connect. I'd also like to use non-blocking asynchronous IO on the client.
In order to try and accomplish this I have tried to use the Socket.BeginConnect method. My intention is that this call will spawn a background thread which would be blocked at the EndConnect call until a connection is established. This way my client can call this method at its startup and then continue operation. Here is my code:
public bool Init_Port(string Host)
{
IPHostEntry ipHostInfo = Dns.Resolve(Host);
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, PORT);
try
{
//Create the connection
My_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
My_Socket.BeginConnect(localEndPoint, new AsyncCallback(Connect_To_Port), My_Socket);
}
catch (Exception e)
{
ErrorHandler(e.Message);
return false;
}
return true;
}
private void Connect_To_Port(IAsyncResult ar)
{
try
{
if (My_Socket != null)
{
//will block the thread until a connection is made
My_Socket.EndConnect(ar);
Connection_Flag = true;
//Setup the asynchronous read
My_Socket.BeginReceive(Rx_Buffer, 0, SOCKET_BUFFER_SIZE, 0,
new AsyncCallback(Read_Port), My_Socket );
}
}
catch (Exception e)
{
ErrorHandler(e.Message);
}
}
I test this without starting the server application. I am hoping that the thread will be blocked at the EndConnect until my server application is started. What I observe is that EndConnect returns immediately and that I get the error message
No connection could be made because the target machine actively refused it 127.0.0.1:50042
Can anyone tell me what I can do to make this asynchronous connect wait for the server application? Thanks in advance.
Can anyone tell me what I can do to make this asynchronous connect wait for the server
application?
Nothing. YOu run it in a loop every X seconds until it starts or you get a logical timeout. TCP will not wait, you have to retry.
Just have the client connect on demand, when the code first needs a connection, according to what the user is doing. If the connection fails, tell the user he can't do that yet, whatever it was.

Start listening again with Socket after a disconnect

I'm writing a small C# Sockets application. Actually I have two, a server and a client.
The user runs the client, enters the IP and port for the server, presses 'connect', and then once connected they can enter text into a textbox and send it to the server.
The server simply displays either "No connection" or "Connection from [ip]:[port]", and the most recent received message underneath.
The server successfully receives messages, and even handles the client disconnect fine.
Now I'm trying to make it listen again after the client has disconnected but for some reason nothing I try will allow it to start listening again.
Here is part of my code:
Socket socket;
private void listen()
{
socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Any, 12345));
socket.Listen(10);
socket.BeginAccept(new AsyncCallback(acceptAsync), socket);
}
and
private void receiveAsync(IAsyncResult res)
{
Socket socket = (Socket)res.AsyncState;
try
{
int nBytes = socket.EndReceive(res);
if (nBytes > 0)
{
Invoke(new MethodInvoker(delegate()
{
lMessage.Text = encoder.GetString(buffer);
}));
setupReceiveAsync(socket);
}
else
{
Invoke(new MethodInvoker(delegate()
{
lConnections.Text = "No Connections.";
lMessage.Text = "No Messages.";
socket.Shutdown(SocketShutdown.Both);
socket.Close();
listen();
}));
}
}
catch { }
}
The last line: listen(); is what throws the error.
I have tried simply calling socket.BeginAccept() again, but that also throws an exception.
The message I'm getting is:
Only one usage of each socket address (protocol/network address/port) is normally permitted
If I don't call my listen() function and instead just call socket.BeginAccept(), then I get "You must first call socket.listen()"
If I call the socket.listen() function, then it tells me it's already connected and cart start listening.
Once I have made an asynchronous connection, and received several asynchronous messages, how then do I begin receiving again?
Your socket variable already has an listening socket assigned to it the second time you call listen(), which is why it tells you only one usage is permitted. All you need to repeat is the socket.BeginAccept(new AsyncCallback(acceptAsync), socket) call. So try replacing the call to listen() inside your receiveAsync(...) method with socket.BeginAccept(new AsyncCallback(acceptAsync), socket).
In async Begin* is always followed by End*. See Using an Asynchronous Server Socket. Your accept method should be something like:
try {
listener.Bind(localEP);
listener.Listen(10);
while (true) {
allDone.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(SocketListener.acceptCallback),
listener );
allDone.WaitOne();
}
} catch (Exception e) {
Server, means that an app that listens on specified port/ip. Is usually, always in a listening mode - that's why it is called a server. It can connect and disconnect a client, but is always in listening mode.
This means, when a server disconnects a client - even then - it is in listening mode; meaning it can accept the incoming connections as well.
Though, disconnection request can come from client or can be forcefully applied by server.
The process for a server is:
Bind to socket
Listen
Accept connections
The process for client is:
Connect to the server
Send/receive messages
There are several ways for server to handle the incoming clients, couple, as follows:
Incoming connections are maintained in a list, for instance within a List<TcpClient>.
One way of handling the incoming clients is through threads. For instance, for each incoming client, spawn a thread that would handle the communication between server and client. For instance, checkout this example.
_
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
Use single thread and use context switching to manage client communications (TX/RX).

How to reuse socket in .NET?

I am trying to reconnect to a socket that I have disconnected from but it won't allow it for some reason even though I called the Disconnect method with the argument "reuseSocket" set to true.
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.Connect(ipAddress, port);
//...receive data
_socket.Disconnect(true); //reuseSocket = true
//...wait
_socket.Connect(ipAddress, port); //throws an InvalidOperationException:
Once the socket has been disconnected,
you can only reconnect again
asynchronously, and only to a
different EndPoint. BeginConnect must
be called on a thread that won't exit
until the operation has been
completed.
What am I doing wrong?
You can set the socket options like this
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, True)
If it does not work, try some other options
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, false)
_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, True)
_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 500)
_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, Timeout)
After reading the MSDN documentation for Socket.Disconnect I noticed something that might be causing your issue.
If you need to call Disconnect without first calling Shutdown, you can set the SocketOption named DontLinger to false and specify a nonzero time-out interval to ensure that data queued for outgoing transmission is sent.
Disconnect then blocks until the data is sent or until the specified time-out expires. If you set DontLinger to false and specify a zero time-out interval, Close releases the connection and automatically discards outgoing queued data.
Try setting the DontLinger Socket option and specify a 0 timeout or use Shutdown before you call disconnect.
Did you try adding this line after Disconnect and before Connect?
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
From MSDN:
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Disconnect(true);
if (client.Connected)
Console.WriteLine("We're still connnected");
else
Console.WriteLine("We're disconnected");
If you are using a connection-oriented protocol, you can use this method to close the socket. This method ends the connection and sets the Connected property to false. However, if reuseSocket is true, you can reuse the socket.
To ensure that all data is sent and received before the socket is closed, you should call Shutdown before calling the Disconnect method.
Socket.Shutdown method waits until all the data in the buffer has been sent or received. However, if we only set linger options, the Socket will shutdown after certain timeout interval.

Categories

Resources