Search code examples
c#socketsnetworkstream

How can I keep connection to server using socket?


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#

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. The code above never show exception message.

Meantime, i have other option using TcpClient

private void _connect()
{
            TcpClient client1 = new TcpClient();
            try
            {               
                client1.Connect("10.10.10.120", 3000);
                NetworkStream stream1 = client1.GetStream();
                var bytes = new byte[256];
                while (true)
                {
                    int numbyte = stream1.Read(bytes, 0, bytes.Length);
                    if (numbyte == 0)
                    {
                        byte[] data_send = Encoding.ASCII.GetBytes("Hi, dummy data");
                        stream1.Write(data_send, 0, data_send.Length);   
                    }
                    else
                    {
                        byte[] byte_rec = new byte[numbyte];
                        Buffer.BlockCopy(bytes, 0, byte_rec, 0, numbyte);
                        txt_log.Text = Encoding.ASCII.GetString(byte_rec);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
}

With this code using Tcpclient, the connection still about 20 seconds, after that the connection will be appear, not show ESTABLISHED or CLOSE_WAIT when i use netstat command to check. But it have exception message is Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.

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

Solution

  • Ok, after more time to debug and enhancement, I get my resolve by myself, I'm not sure if you all get same issue, but it working well until now for me. The key in here , just look at the finally code and changed something. Like this below, thank for all advices.

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