Click here to Skip to main content
15,886,919 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
i have connection to the server. After connected successfully, I can see the connection via CMD netstat command netstat -a -n. But after about 21 seconds, the connection changing from ESTABLISHED to CLOSE_WAIT . I want to the connection always is ESTABLISHED . How can i do it ?

This is from netstat command, the result in the first time and second time.

TCP 192.168.10.12:50148 10.10.10.120:3000 ESTABLISHED
TCP 192.168.10.12:50148 10.10.10.120:3000 CLOSE_WAIT
This is my snipped code in C#

C#
private void _connect()
{
            var IpEndPoint = new IPEndPoint(IPAddress.Parse("10.10.10.120"), 3000);
            var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
            client.SendTimeout = 60;
            client.ReceiveTimeout = 60;
            try
            {
                client.Connect(IpEndPoint);
                int byteCount = 0;
                byte[] bytes = new byte[256];
                while (true)
                {
                    byteCount = client.Receive(bytes);
                    if (byteCount == 0) //not receive anything from server, client will send dummy data to server
                    {
                        byte[] data_send = Encoding.ASCII.GetBytes("Hi, dummy data");
                        client.Send(data_send);
                    }
                    else //receive data from server, write it to log files.
                    {
                        byte[] byte_rec = new byte[byteCount];
                        Buffer.BlockCopy(bytes, 0, byte_rec, 0, byteCount);
                        txt_log.Text = Encoding.ASCII.GetString(byte_rec);
                    }  
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
}

I try debug more time, but it only can be run few seconds, after that the connection will be changed from ESTABLISHED to CLOSE_WAIT.


So far, I found some option and enhancement my code. However, when I debug, I can see stream with properties DataAvailable is true at the first time loop. After that, the second time loop, it's always is false. If don't put break point and run with this code, it's can keep connection about more than 10min. But when I put break point at this line numberOfBytesRead = stream.Read(myReadBuffer, 0, myReadBuffer.Length);, it only run at the first time loop, without next time because stream is false. The time delay when run first time to second time loop about 52s. After that, the connection is break. I get this exception : 'Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.' . Can you tell me why stream changed from true to false after first time loop ?. This way stuck and let my code is wrong.

private async void _connect()
  {
            var serverEndpoint = new IPEndPoint(IPAddress.Parse(_ip), _port);
            client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                client.Connect(serverEndpoint);
                client.NoDelay = true;
                client.SendTimeout = 60000;
                client.ReceiveTimeout = 60000;
                byte[] myReadBuffer = new byte[1024];
                int numberOfBytesRead = 0;
                bool _flag = false;             
                while (true)
                {
                    stream = new NetworkStream(client); //create stream based on socket
                    if (stream.CanRead)
                    {
                        do
                        {
                            if (_flag)
                            {
                                numberOfBytesRead = 0;
                                goto receiveskip;
                            }
                            if (numberOfBytesRead == 0) //send dummy data to server first
                            {
                                byte[] data_dummy = Encoding.ASCII.GetBytes("dummy_abc");
                                stream.Write(data_dummy, 0, data_dummy.Length);
                                stream.Flush();
                            }
                            numberOfBytesRead = stream.Read(myReadBuffer, 0, myReadBuffer.Length);
                            byte[] bytes_rec = new byte[numberOfBytesRead];
                            Buffer.BlockCopy(myReadBuffer, 0, bytes_rec, 0, numberOfBytesRead);                         
                            //client receive data from server at the first time, after sent dummy_abc to server
                            if(bytes_rec.Length == 14) 
                            {
                                txt_log.Text += Encoding.ASCII.GetString(bytes_rec); //write to textbox
                            }
                            //receive data from server at second time and so on. 
                            //After server get data from client and reply first time, server will send data
                            //server will send data with bytes lengh more 14
                            if (bytes_rec.Length > 14)
                            {
                                byte[] data_rep = Encoding.ASCII.GetBytes("Ok, thank server"); //client reply to server 
                                stream.Write(data_rep, 0, data_rep.Length);
                                stream.Flush();
                                _flag = true;
                                continue;
                            }
                        }
                        while (stream.DataAvailable);
                    }
                    else
                    {
                        MessageBox.Show("Cannot read from this NetworkStream.");
                    }
                }
            }
            catch (Exception ex)
            {
                stream.Close();
                client.Close();
                MessageBox.Show(ex.Message);
            }
  } 


What I have tried:

I try debug more time, but it only run about 21 seconds, after that the connection will be changed from ESTABLISHED to CLOSE_WAIT
Posted
Updated 26-Jul-23 23:41pm
v2

Have you thought about using SignalR[^] instead? It's robust and simple to use, so you can focus on your application.

Alternatively, you could use an open source lib like GitHub - nterry/AwesomeSockets: A fast, lightweight, and easy to use socket library for C#.[^] or use it as a learning tool to help you build your own. All of the key issues are already sorted out for you!

If you want to look at other libs, try this: c# socket library - Google Search[^]
 
Share this answer
 
v2
Comments
headshot9x 17-Jul-23 7:30am    
I want to know what's happen in my code, anything wrong from my side or not? And any idea for solution of my code.
Graeme_Grant 17-Jul-23 7:33am    
I don't do socket programming. But if I was you, those are the options that I would look at using.
headshot9x 17-Jul-23 7:39am    
Yes, i hopefully receive from socket. By the way, some reference usefully from you .
Graeme_Grant 17-Jul-23 7:45am    
You have not posted enough code to see both sides of the conversation. But again, I am not a socket programmer, so I am the wrong person to debug your code for you. Again, I have given you access to the source code for a working solution. If not that one, there are several others to choose from.
headshot9x 20-Jul-23 5:36am    
I have update more description and enhancement my code.
There is an article on how to keep your connection live here on CodeProject - Set Keep-Alive Values[^]

Another discussion found at - TCP keepAlive settings problem[^]

My code below based on this link - C# Setting Socket Keep-Alive[^] might be what you are looking for. I am not versed in socket code and did not test this against anything, hope it points you in the right direction though -
C#
private void _connect()
{
    var IpEndPoint = new IPEndPoint(IPAddress.Parse("10.10.10.120"), 3000);
    var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
    client.SendTimeout = 60;
    client.ReceiveTimeout = 60;
    
    try
    {
        client.Connect(IpEndPoint);
        
        client.NoDelay = true;

        //Send keep-alive packet to keep the connection alive, see the links I provided on the methods
        byte[] keepAlivePacket = Encoding.ASCII.GetBytes("Keep alive");
        client.Send(keepAlivePacket);

        int byteCount = 0;
        byte[] bytes = new byte[256];

        while (true)
        {
            byteCount = client.Receive(bytes);

            if (byteCount == 0)
            {
                byte[] data_send = Encoding.ASCII.GetBytes("Hi, dummy data");
                client.Send(data_send);
            }
            else
            {
                byte[] byte_rec = new byte[byteCount];
                Buffer.BlockCopy(bytes, 0, byte_rec, 0, byteCount);
                txt_log.Text = Encoding.ASCII.GetString(byte_rec);
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}


See more on the Encoding.GetBytes documentation at - MS Learn Encoding.GetBytes Method[^]

The CodeProject link still has the best description on how to do this.
 
Share this answer
 
Comments
headshot9x 18-Jul-23 6:35am    
Hi, for your reference link, it's same my case, checking this line client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); . The issue still not working, it can be established , but changed to close_wait after 20 seconds
Andre Oosthuizen 18-Jul-23 7:15am    
Did you add this line - 'byte[] keepAlivePacket = Encoding.ASCII.GetBytes("Keep alive");'? It is the packet that will keep it alive.
headshot9x 18-Jul-23 7:46am    
Yes, i tried but still not working.
headshot9x 20-Jul-23 5:37am    
I have changed something in my code, it can be run more than 10min but still get stuck.
You haven't stated whether your exception handler gets called - if it does it would be interesting to know the exception. It's hard to know exactly what's going on here without a debugger..

That said, the timeouts you have (60) are in milliseconds, not seconds. The minimum it will accept and rounds up to is 500, so it's possible that you are sending the dummy string twice a second. CLOSE_WAIT suggests that it is the server on the other end which it terminating the connection - could it be that it doesn't like that many dummy messages being sent? First thing I'd try is setting the timeouts to 60,000 and see what that does.
 
Share this answer
 
Comments
headshot9x 18-Jul-23 6:36am    
Hi, i changed to your mention, but still not working. client.SendTimeout = 60000;
client.ReceiveTimeout = 60000;
Rob Philpott 18-Jul-23 10:01am    
As mentioned above, it appears to be the server that is disconnecting you. Could it be that its expecting a secure connection - TLS or something?
headshot9x 18-Jul-23 21:19pm    
But how can, in debug mode, i do like this, 1) start it. 2) check in CMD , see it is established between client and server. 3) After 20s, check in CMD again, it is close_wait. That's it.
Andre Oosthuizen 19-Jul-23 6:00am    
The 'CLOSE_WAIT' state generally happen when your remote server calls a connection closure process, and your application doesn't properly acknowledge or handle the server's FIN signal.

You need to ensure that your application properly handles the received data and that the server is also sending closure signals when it intends to close the connection.

Keep in mind taht there is no guaranteed way to prevent your server from initiating the connection closure, as that is handled by the server. Some servers may close idle connections to save resources.

As mentioned, I am not good in socket code. I added a timer to keep checking for closing signals, not sure if this is even remotely feasible -

using System.Threading;

//Your other code...

private void SendKeepAlive(Socket client)
{
    byte[] keepAlivePacket = Encoding.ASCII.GetBytes("Keep alive");
    client.Send(keepAlivePacket);
}

private void _connect()
{
    //Your existing code...

    Timer keepAliveTimer = new Timer(state => SendKeepAlive(client), null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));

    try
    {
        //Other code...

        while (true)
        {
            byteCount = client.Receive(bytes);

            //Code...
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}
headshot9x 20-Jul-23 5:39am    
I see your idea, this is same I try before. By the way, I have updated my enhancement code and get stuck with stream.DataAvailable . I need to resolve this one. You can look my post again.
After spend more time to debug and see transfer data, I get this one, and it's working well until now for me. So, if anyone get the issue like me, can try this way below

private async void _connect()
  {
            var serverEndpoint = new IPEndPoint(IPAddress.Parse(_ip), _port);
            var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                client.SendTimeout = 180000;
                client.ReceiveTimeout = 180000;         
                await client.ConnectAsync(serverEndpoint);
                byte[] myReadBuffer = new byte[1024];
                int numberOfBytesRead = 0;
                bool _flag = false;             
                var stream = new NetworkStream(client); 
                while (true)
                {
                            if (_flag)
                            {
                                numberOfBytesRead = 0;
                                goto receiveskip;
                            }
                            if (numberOfBytesRead == 0) //send dummy data to server first
                            {
                                byte[] data_dummy = Encoding.ASCII.GetBytes("dummy_abc");
                                await stream.WriteAsync(data_dummy, 0, data_dummy.Length);
                                await stream.FlushAsync();
                                _flag = true;
                            }
                            receiveskip:
                            numberOfBytesRead = await stream.ReadAsync(myReadBuffer, 0, myReadBuffer.Length);
                            byte[] bytes_rec = new byte[numberOfBytesRead];
                            Buffer.BlockCopy(myReadBuffer, 0, bytes_rec, 0, numberOfBytesRead);                         
                            //client receive data from server at the first time, after sent dummy_abc to server
                            if(bytes_rec.Length == 14) 
                            {
                                txt_log.Text += Encoding.ASCII.GetString(bytes_rec); //write to textbox
                                _flag = true;
                                goto receiveskip;
                            }
                            //receive data from server at second time and so on. 
                            //After server get data from client and reply first time, server will send data
                            //server will send data with bytes lengh more 14
                            if (bytes_rec.Length > 14)
                            {
                                byte[] data_rep = Encoding.ASCII.GetBytes("Ok, thank server"); //client reply to server 
                                await stream.WriteAsync(data_rep, 0, data_rep.Length);
                                await stream.FlushAsync();
                                _flag = true;
                                goto receiveskip;
                            }
                            if (bytes_rec.Length == 0)
                            {
                              break;
                            }
                }
            }
            catch (Exception ex)
            {
                client.Close();
                MessageBox.Show(ex.Message);
            }
  } 
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900