C# TcpClinet LingerOption with Close() not skips TIME_WAIT - c#

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();

Related

C# SocketException: Address already in use

I am trying to establish a connection through Sockets to send data (for testing purposes to the local IP address, meaning the computer is sending data to "itself").
Previously, everything worked perfectly fine for weeks throughout the development, meaning the connection could be established, the data could be sent and received and the connection could finally be closed, but a few days later, also after restarting my router, I am getting a SocketException (98) when trying to bind the "listener" Socket to an end point with IPAddress.Any (0.0.0.0) with the message: Address already in use.
The source code has not changed in between. The Socket is supposed to accept any connection from any IP-Address, as it is the "listener" Socket for receiving data.
I am using .NET 6.0.301.
This is a simplified version of the relevant source code:
// In the constructor of the base-class:
IpEndPoint = new IPEndPoint(IPAddress.Any, Port); // Random unused port that also hasn't changed
// ...
// Gets called in the constructor of the derived class
private async Task ReceiveDataAsync()
{
using Socket listener = new(IpEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
try
{
listener.Bind(IpEndPoint); // Fails here!!!
listener.Listen(100);
}
catch(Exception e)
{
Console.WriteLine(e);
throw;
}
while(true)
{
using Socket handler = await listener.AcceptAsync();
// Receive data...
}
}
This method is called only once and the exception throws at the very first cycle of the loop. It is called, of course, long before the attempt to establish a connection to this IP.
It might also be important noting that I didn't close the connection after receiving the data with the Shutdown, DisconnectAsync and Close methods, but this has always been done on the client side after the data had been sent.
And here is the exception:
System.Net.Sockets.SocketException (98): Address already in use
at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
at ....ReceiveDataAsync() ...
EDIT:
This is the output of netstat -ntpl | grep 0.0.0.0 while my IDE, JetBrains Rider is running with the relevant project being opened (but it isn't executing):
tcp 0 0 0.0.0.0:31415 0.0.0.0:* LISTEN
10064/dotnet
tcp 0 0 127.0.0.1:42103 0.0.0.0:* LISTEN
9560/Rider.Backend
tcp 0 0 127.0.0.1:33747 0.0.0.0:* LISTEN
9560/Rider.Backend
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN
-
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN
-
Killing the process, which occupies the port, doesn't have much of an effect, as a new process gets created when I launch the application again.
A Bind on a fixed endpoint inside a while (true) is hugely suspicious. You only need to bind once - a single listener socket can accept any number of client connections. Refactor the code so you only bind and listen once, and then just have the accept in the while loop.
If it can't bind even the first time, then that suggests a rogue process is holding the port, or possibly a firewall problem. But my money would be on a rogue process. If you can't find it, try rebooting - if that fixes it: it was a rogue process (probably your own program started from a debugger, or similar).

c# fixed tcp client local endpoint port causes SocketException

Can i unbind socket from local endpoint? For security purposes, i need to fix source port for TCP communication. In this client code i fix source port to 42448:
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
IPEndPoint localEP = new IPEndPoint(IPAddress.Parse("192.168.1.123"), 42448);
s.Bind(localEP);
s.Connect(remoteEP);
s.Send(new byte[] { 0x01, 0x02, 0x03 });
s.Close();
It works only once. Second time it throws SocketException (that address already in use) on the s.Connect line as i see in netstat, there is one connection from this source port 42448 with TIME_WAIT state, even if i close the app. after about 1 minute this TIME_WAIT connection disappears and i can run my code, but again just once. how can i properly unbind this socket so i can run code many times?
Update 1
it is not a server socket, so there is no listening here. LingerOption is also doesnt work:
LingerOption lo = new LingerOption(false, 0);
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);

C# .Net Socket Server Client

I've got a little problem with the .Net Sockets in C#.
I programmed a client and a server working with TCP.
As the client is opened it sends a handshake to the server. The server answers with it's state (clientexists, clientaccepted,...). After that the application sends a getdata-request, abandons the connection and listens for the server's 'response'. Now, the server builds a connection to the client and sends all the data the client needs.
The code and everything else works, but the problem:
On our company testserver it works fine, on the live server only the handshake works. After it the client doesn't receive any more data. Serverapplication is the same on both servers.
I thought the problem was caused by some firewall (server wants to build a tcp connection to the client -> not good), but the system administrator said there is no firewall that could block that.
Now I'm searching for a ('cheap') solution that doesn't take too much time and changes in code. If anyone knows how to theoretically solve that, that would be great.
BTW: I am not allowed to do anything on the live server other than run the serverapplication. I don't have the possibility to debug on this server.
I can't publish all of my code, but if you need to see specific parts of it, ask for it please.
---EDIT---
Client-Server communication
1) Client startup
Client send handshake (new tcp connection)
2) Server validates handshake and saves IP
Server responds with it's client state (same tcp connection)
3) Client acknowledges this response and abandons this connection
Client sends getdata-request (new tcp connection)
Client abandons this tcp connection, too
4) Server receives getdata-request and collects the needed data in the main database
Server sends all the collected data to the client (multiple tcp connections)
5) Client receives all data and displays it in it's GUI (multiple tcp connections and the order of the data is kept by working with AutoResetEvents and Counts of sockets to send)
This is the main part my code does. It's by far not the best but it was for me as I wrote it I guess. Step one, two and three work as intended. The processing of the data works fine, too.
Another thing i forgot to mention is that the solution uses two Ports '16777' and '16778'. One to receive/listen and one to send.
My code is based on the MSDN example of the asynchronous server and client.
Sending a handshake (and getdata-request)
public void BeginSend(String data)
{
try
{
StateObject state = new StateObject();
state.workSocket = sender;
byte[] byteData = Encoding.UTF8.GetBytes(data);
sender.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback((IAsyncResult e) =>
{
Socket socket = (Socket)e.AsyncState;
SocketBase.StateObject stateObject = new SocketBase.StateObject();
stateObject.workSocket = socket;
socket.BeginReceive(stateObject.buffer, 0, 256, SocketFlags.None, new AsyncCallback(this.ReadCallback), (object)stateObject);
}), sender);
sender = RetrieveSocket(); //Socketreset
Thread.Sleep(100);
}
catch /*(Exception e)*/
{
//--
}
}
Server listener
public void StartListening()
{
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(System.Int32.MaxValue);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
//--
}
}
public void AcceptCallback(...);
public void ReadCallback(...);
Socket send
private void Send(Socket handler, String data)
{
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.UTF8.GetBytes(data);
// Begin sending the data to the remote device.
t.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), t);
}
Socket send all data part (answer to getdata-request | socToHandle should be the socket of the previous connection of the getdata-request)
private void SendAllData(Socket socToHandle, string PakContent)
{
#region IsThereADatetime? //Resolve a given datetime
#region GiveClientNumberOfPackets //Send the client info about how much he has to receive (See line below)
Send(socToHandle, "ALERT#TASKCOUNT;OPT-" + GetBestDate(dateStart) + EndSocket);
#region #SendResouces
#region #SendGroups
#region #SendTasks
}
Looking through my old code I have one idea =>
Could I send everything over the same connection by changing:
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
(which creates a new connection) to something that uses the same connection?
If that would work, how can I do that?
And would the listener part of the client still receive single packets?
Servers and their environment are configured to handle incoming requests properly. Clients are usually behind a router, which by default make them unable to receive incoming connections from outside their network (a good thing).
To enable incoming connections, you could configure your router to forward all requests for a certain port number to your machine. No one else on your network would be able to run the client then, though.
This is why in a typical multiple clients-single server environment, the client makes all the connections, and only the server requires any changes to the network landscape.
I don't know why you chose to connect to the clients from the server side, but I would strongly advise against this - any cheap solution that uses this mechanism may turn out to be very expensive in the end.

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;

Question about listening and backlog for sockets

I am writing an application in C# that needs to handle incoming connections and I've never done server side programming before. This leads me to these following questions:
Pros and cons of high backlog / low backlog? Why shouldn't we set the backlog to a huge number?
If I call Socket.Listen(10), after 10 Accept()s do I have to call Listen() again? Or do I have to call Listen() after every Accept()?
If I set my backlog to 0 and hypothetically two people want to connect to my server at the same time, what would happen? (I am calling Socket.Select in a loop and checking readability of the listening socket, after I handle the first connection would the second connection be successful upon the next iteration if I called Listen() again?)
Thanks in advance.
The listen backlog is, as Pieter said, a queue which is used by the operating system to store connections that have been accepted by the TCP stack but not, yet, by your program. Conceptually, when a client connects it's placed in this queue until your Accept() code removes it and hands it to your program.
As such, the listen backlog is a tuning parameter that can be used to help your server handle peaks in concurrent connection attempts. Note that this is concerned with peaks in concurrent connection attempts and in no way related to the maximum number of concurrent connections that your server can maintain. For example, if you have a server which receives 10 new connections per second then it's unlikely that tuning the listen backlog will have any affect even if these connections are long lived and your server is supporting 10,000 concurrent connections (assuming your server isn't maxing out the CPU serving the existing connections!). However, if a server occasionally experiences short periods when it is accepting 1000 new connections per second then you can probably prevent some connections from being rejected by tuning the listen backlog to provide a larger queue and therefore give your server more time to call Accept() for each connection.
As for pros and cons, well the pros are that you can handle peaks in concurrent connection attempts better and the corresponding con is that the operating system needs to allocate more space for the listen backlog queue because it is larger. So it's a performance vs resources trade off.
Personally I make the listen backlog something that can be externally tuned via a config file.
How and when you call listen and accept depends upon the style of sockets code that you're using. With synchronous code you'd call Listen() once with a value, say 10, for your listen backlog and then loop calling Accept(). The call to listen sets up the end point that your clients can connect to and conceptually creates the listen backlog queue of the size specified. Calling Accept() removes a pending connection from the listen backlog queue, sets up a socket for application use and passes it to your code as a newly established connection. If the time taken by your code to call Accept(), handle the new connection, and loop round to call Accept() again is longer than the gap between concurrent connection attempts then you'll start to accumulate entries in the listen backlog queue.
With asynchronous sockets it can be a little different, if you're using async accepts you will listen once, as before and then post several (again configurable) async accepts. As each one of these completes you handle the new connection and post a new async accept. In this way you have a listen backlog queue and a pending accept 'queue' and so you can accept connections faster (what's more the async accepts are handled on thread pool threads so you don't have a single tight accept loop). This is, usually, more scalable and gives you two points to tune to handle more concurrent connection attempts.
What the backlog does is provide a queue with clients that are trying to connect to the server, but which you haven't processed yet.
This concerns the time between when the client actually connects to the server and the time you Accept or EndAccept the client.
If accepting a client takes a long time, it is possible that the backlog becomes full and new client connections will be rejected until you had time to process clients from the queue.
Concerning your questions:
I don't have information on that. If the default number does not pose any problems (no rejected client connections) leave it at its default. If you see many errors when new clients want to connect, increase the number. However, this will probably be because you take too much time accepting a new client. You should solve that issue before increasing the backlog;
No, this is handled by the system. The normal mechanism of accepting clients takes care of this;
See my earlier explanation.
Try this program and you will see what is backlog good for.
using System;
using System.Net;
using System.Net.Sockets;
/*
This program creates TCP server socket. Then a large number of clients tries to connect it.
Server counts connected clients. The number of successfully connected clients depends on the BACKLOG_SIZE parameter.
*/
namespace BacklogTest
{
class Program
{
private const int BACKLOG_SIZE = 0; //<<< Change this to 10, 20 ... 100 and see what happens!!!!
private const int PORT = 12345;
private const int maxClients = 100;
private static Socket serverSocket;
private static int clientCounter = 0;
private static void AcceptCallback(IAsyncResult ar)
{
// Get the socket that handles the client request
Socket listener = (Socket) ar.AsyncState;
listener.EndAccept(ar);
++clientCounter;
Console.WriteLine("Connected clients count: " + clientCounter.ToString() + " of " + maxClients.ToString());
// do other some work
for (int i = 0; i < 100000; ++i)
{
}
listener.BeginAccept(AcceptCallback, listener);
}
private static void StartServer()
{
// Establish the locel endpoint for the socket
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, PORT);
// Create a TCP/IP socket
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen
serverSocket.Bind(localEndPoint);
serverSocket.Listen(BACKLOG_SIZE);
serverSocket.BeginAccept(AcceptCallback, serverSocket);
}
static void Main(string[] args)
{
StartServer();
// Clients connect to the server.
for (int i = 0; i < 100; ++i)
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint remoteEP = new IPEndPoint(ipAddress, PORT);
// Create a TCP/IP socket and connect to the server
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEP, null, null);
}
Console.ReadKey();
}
}
}

Categories

Resources