0
votes

I have a problem with connection handling in TCP Client socket.

This code should connect to localhost at 4444 port and listening for all incoming data from this TCP Server.

I need to write connection handling for this. For example if while attempting to connect server is not responding it should trying to connect again, or if connection is ready and after receiving some data TCP server will close the connection TCP client should try to reconnect again.

Can anyone help me with this problems

Here is what I have in this moment

using UnityEngine;
using System.Collections;
using System;
using System.Net;
using System.Net.Sockets;

public class TCPClientNew : MonoBehaviour {

    private Socket _clientSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
    private byte[] _recieveBuffer = new byte[8142];

    private void StartClient()
    {
        try
        {
            _clientSocket.Connect(new IPEndPoint(IPAddress.Loopback,4444));
        }
        catch(SocketException ex)
        {
            Debug.Log(ex.Message);

            // Try to reconnect ??  TODO
        }
        Debug.Log ("connected");

        _clientSocket.BeginReceive(_recieveBuffer,0,_recieveBuffer.Length,SocketFlags.None,new AsyncCallback(ReceiveCallback),null);

    }

    private void ReceiveCallback(IAsyncResult AR)
    {
        //Check how much bytes are recieved and call EndRecieve to finalize handshake
        int recieved = _clientSocket.EndReceive(AR);

        if(recieved <= 0)
            return;

        //Copy the recieved data into new buffer , to avoid null bytes
        byte[] recData = new byte[recieved];
        Buffer.BlockCopy(_recieveBuffer,0,recData,0,recieved);


        //Processing received data
        Debug.Log (System.Text.Encoding.ASCII.GetString(recData));



        //Start receiving again
        _clientSocket.BeginReceive(_recieveBuffer,0,_recieveBuffer.Length,SocketFlags.None,new AsyncCallback(ReceiveCallback),null);
    }

    private void SendData(byte[] data)
    {
        SocketAsyncEventArgs socketAsyncData = new SocketAsyncEventArgs();
        socketAsyncData.SetBuffer(data,0,data.Length);
        _clientSocket.SendAsync(socketAsyncData);
    }

    void Start()
    {
        StartClient ();
    }
}
1

1 Answers

1
votes

What you want is a way to keep retrying the connection if it fails. And if there is an exception during a read, you want to see if we're still connect and if not then re-connect. I added a loop in the Connect() method to retry the connect after waiting for 1 second.

In the receive callback, I put a try/catch and if there is an exception I will go back to the Connect() method to retry the connection.

public class TCPClientNew
{

    private Socket _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    private byte[] _recieveBuffer = new byte[8142];

    private void Connect()
    {
        bool isConnected = false;

        // Keep trying to connect
        while (!isConnected)
        {
            try
            {
                _clientSocket.Connect(new IPEndPoint(IPAddress.Loopback, 4444));
                // If we got here without an exception we should be connected to the server
                isConnected = true;
            }
            catch (SocketException ex)
            {
                Debug.Log(ex.Message);

                // Wait 1 second before trying to connect again
                Thread.Sleep(1000);
            }
        }

        // We are now connected, start to receive
        _clientSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
    }

    private void ReceiveCallback(IAsyncResult AR)
    {
        //Check how much bytes are recieved and call EndRecieve to finalize handshake
        try
        {
            int recieved = _clientSocket.EndReceive(AR);

            if (recieved <= 0)
                return;

            //Copy the recieved data into new buffer , to avoid null bytes
            byte[] recData = new byte[recieved];
            Buffer.BlockCopy(_recieveBuffer, 0, recData, 0, recieved);

            //Start receiving again
            _clientSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
        }
        catch (SocketException ex)
        {
            Debug.Log(ex.Message);

            // If the socket connection was lost, we need to reconnect
            if (!_clientSocket.Connected)
            {
                Connect();
            }
            else
            {
                //Just a read error, we are still connected
                _clientSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
            }
        }
    }

    private void SendData(byte[] data)
    {
        SocketAsyncEventArgs socketAsyncData = new SocketAsyncEventArgs();
        socketAsyncData.SetBuffer(data, 0, data.Length);
        _clientSocket.SendAsync(socketAsyncData);
    }
}