How to reuse socket in .NET? - c#

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.

Related

C# TcpClinet LingerOption with Close() not skips TIME_WAIT

I am trying to contact to server with C# TcpClient for lots of time. For example, I connect to server for 5s, disconnect then try connect to server in 10s, and repeat...
But eventhogh I set LingerOption and ResueAddress Option as true, ExtendedSocketExcption came out when I reconnect to server.
Here is my code. (.Net5, Windows 10)
TCPSocket = new TcpClient(new IPEndPoint("10.10.0.100", 50010));
TCPSocket.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
LingerOption lo = new LingerOption(true, 0);
TCPSocket.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);
TCPSocket.Connect(new IPEndPoint("10.10.0.50", 50010));
TCPSocket.ReceiveTimeout = 5000;
//Do somthing
TCPSocket.Client.Shutdown(SocketShutdown.Both);
TCPSocket.Close();
Thread.Sleep(5000);
TCPSocket.Connect(new IPEndPoint(SRE3021IP, SRE3021TCPPort)); //ExtendedSocketExeption
And I check on cmd with command netstat -ano | findstr 50010 while thread was sleeping.
TCP 10.10.0.100:50010 10.10.0.50:50010 TIME_WAIT 0
The TIME_WAIT state remained about 30~1 min then It disappeared...
I don't know why linger option was not applied.
Setting a LingerOption doesn't stop a socket from closing. It delays the close() to allow any unsent data in the buffer to be sent. This allows an application to move on to the next phase with a slow network. The socket will still close.
ReuseAddress has nothing to do with reusing an existing socket (believe it or not), it allows a Listening Socket to bind to an existing listening port. This is a very bespoke behaviour and requires other process interops to have two different applications listening on the same port. This option has no useful meaning on an outbound socket connection.
Your problem stems from the fact you're setting a source bind with this line:
TCPSocket = new TcpClient(new IPEndPoint("10.10.0.100", 50010 ));
If you want to set a source port you have no option but to wait for the OS to clean out the socket from the connection list which means waiting for the TIME_WAIT to expire.
If you don't want to set a source port, (and these days their are very few reasons to actually set a source port) but still want to select a specific source IP address interface then you can use:
TCPSocket = new TcpClient(new IPEndPoint("10.10.0.100", 0));
If you want Windows to just choose the most appropriate outgoing interface, (and port), then use:
TCPSocket = new TcpClient();

Socket not connected exception after calling EndAccept and accessing RemoteEndPoint

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;
}
}

C# (socket) wait for connection during x seconds

I'm making a client socket. This socket will send some data to another socket and wait for its response (if any). I want my client socket to wait for a response for 5 seconds. The problem is, if I put it in Receiver mode, the program will only run after it gets a connection. I want my program to be listening for a duration of time, not until he gets a response (witch could be never, if the other socket isn't programmed to answer).
The Socket class contains a ReceiveTimeout property, which by default is Infinite.
https://msdn.microsoft.com/en-us/library/system.net.sockets.socket.receivetimeout(v=vs.110).aspx
If you set this value, then the Socket.Recieve() method will only block until the timeout has passed, then will throw a TimeoutException.
Socket sock;
//socket connection and sending data
sock.ReceiveTimeout = 5000;
try {
data = sock.Receive();
}
catch (TimeoutException ex)
{
// it never answered
}

C# socket connection keeps sending data after disconnect and close

I have a "start" and "stop" button. When clicking the start button, a new socket is created and a connection is made. When clicking the stop button the socket is shutdown, disconnected, closed and disposed to make sure it is completely gone.
At least, that's what I thought: when clicking start after stopping the connection, a new socket is made etc. but as soon as I send data, the data is sent x amount of times I had created a socket (thus, x amount of times I had clicked the start button).
This is the code for the start:
soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Socket soc; is declared at class-level
System.Net.IPAddress ipAdd = System.Net.IPAddress.Parse(IP);
System.Net.IPEndPoint remoteEP = new IPEndPoint(ipAdd, port);
try
{
soc.Connect(remoteEP);
soc.Send(jsonSettings);
}
catch (SocketException e)
{
MessageBox.Show("Could not connect to socket");
}
And this is the stop code:
if (soc != null)
{
soc.Shutdown(SocketShutdown.Both);
soc.Disconnect(false);
soc.Close();
soc.Dispose();
}
This is used within a VSTO PowerPoint add-in application if this could cause any additional specialties, when the connection is made I'm sending string data to a Python server listening to this port. Each time a connection is closed, the Python server will get out of it's listen-for-data loop and get back in it's waiting for connection state (for the multiple start/stop connections).
Code for sending data:
// this is called each time the user goes to another slide in the PowerPoint presentation
byte[] byData = System.Text.Encoding.ASCII.GetBytes(stringValue);
soc.Send(byData);
Can anyone point out what I'm doing wrong why the socket connections somehow keep on living and sending data even though I disconnected and closed them?
The observed behavior is the whole point and desired outcome from clean shutdown. From the MSDN page for Socket.Shutdown():
When using a connection-oriented Socket, always call the Shutdown method before closing the Socket. This ensures that all data is sent and received on the connected socket before it is closed.
The call to Shutdown() prevents your application from queuing additional outgoing data, it does not stop the network stack from sending data already buffered.
Since you are using a stream socket, how about declaring a network stream for your socket like this:
NetworkStream stream = new NetworkStream(soc);
Then flushing this after each send (and before closing the socket):
stream.Flush();
Also ensure you turn off Nagle's algorithm when you create the socket - it will prevent batching up items on the socket:
soc.NoDelay = true;

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).

Categories

Resources