Таймаут сокета TCP - PullRequest
       13

Таймаут сокета TCP

0 голосов
/ 18 февраля 2019

Я написал программу на C #, которая отправляет данные только с сервера на клиент.Проблема заключается в том, что время между отправкой данных является изменяемым (макс. 5 минут), что иногда приводит к истечению времени ожидания соединения.

Когда я отправляю данные каждые 3 секунды, ни у одного из них не возникает тайм-аут.Но если сообщение отправляется через 5 минут, на клиенте возникает проблема с его получением.

Я сделал функцию тайм-аута, которая есть и у клиента, и у сервера.После тайм-аута каждый переподключается:

public class TimerControl
{
    private System.Timers.Timer timeoutTimer = null;

    public void initTimeout(int timeMS, System.Timers.ElapsedEventHandler funct)
    {
        timeoutTimer = new System.Timers.Timer();
        timeoutTimer.Interval = timeMS; //MS
        timeoutTimer.Elapsed += funct;
        timeoutTimer.AutoReset = true;
        setTimeoutTimer(false);
    }

    public void setTimeoutTimer(bool state)
    {
        if (timeoutTimer != null)
        {
            timeoutTimer.Stop();
            timeoutTimer.Enabled = state;
            if (state) timeoutTimer.Start();
        }
    }
    public void resetTimeoutTimer()
    {
        if (timeoutTimer != null && timeoutTimer.Enabled)
        {
            timeoutTimer.Stop();
            timeoutTimer.Start();
        }
    }
}

, который не решил проблему.

Что я должен сделать, чтобы заставить его работать правильно, а не по истечении времени ожидания?

Сервер:

public class TCPserver :TCPunit
{
    private int    TIMEOUT_MS  = 5000;

    Socket        serverListener = null;
    Queue<string> dataQueued     = null;

    bool isConnectedForced = false;



    public TCPserver()
    {
        dataQueued = new Queue<string>();

        initTimeout(TIMEOUT_MS, reconnect);
    }

    public void sendDataToClient(string message)
    {
        dataQueued.Enqueue(message + Environment.NewLine);
        if(isConnectedForced) startListening();
        if (dataQueued.Count > 0) setTimeoutTimer(true);
    }

    public bool connect(string adress)
    {
        this.thisUnitAdress = adress;
        isConnectedForced = true;
        loopedConnect();
        startListening();
        return true;
    }

    public bool disconnect()
    {
        isConnectedForced = false;
        loopedDisconnect();
        return true;
    }

    private bool loopedConnect()
    {

        try
        {
            IPAddress ipAddress = IPAddress.Parse(this.thisUnitAdress);
            IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);

            if (serverListener != null) loopedDisconnect();

            serverListener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            serverListener.Bind(localEndPoint);

            Console.WriteLine("SERVER connected to: " + this.thisUnitAdress + " port : " + port.ToString());
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine("!!! SERVER connect");
            setTimeoutTimer(true);
            return false;
        }
    }

    private bool loopedDisconnect()
    {
        setTimeoutTimer(false);
        if (serverListener != null)
        {
            if (serverListener.Connected) serverListener.Shutdown(SocketShutdown.Both);
            serverListener.Close();
            Console.WriteLine("SERVER CLOSED!");
            serverListener = null;
        }
        return true;
    }


    private void reconnect(Object source, System.Timers.ElapsedEventArgs e)
    {
        if (isConnectedForced)
        {
            Console.WriteLine("SERVER RECONNECT!!!");
            loopedDisconnect();
            loopedConnect();
            if (dataQueued.Count > 0) setTimeoutTimer(true);
            else setTimeoutTimer(false);
        }
        else
        {
            setTimeoutTimer(false);
        }
    }

    private void startListening()
    {
        try
        {
            serverListener.Listen(100);
            Console.WriteLine("SERVER Waiting for a connection...");
            serverListener.BeginAccept(new AsyncCallback(AcceptCallback), serverListener);
            setTimeoutTimer(true);
        }
        catch (Exception ex)
        {
            Console.WriteLine("!!! SERVER sendingLOOP");
            setTimeoutTimer(true);
        }
    }

    private void AcceptCallback(IAsyncResult ar)
    {
        try
        {
            Socket listener = (Socket)ar.AsyncState;
            Socket handler = listener.EndAccept(ar);

            //HERE SEND
            while (dataQueued.Count > 0)
            {
                string data = dataQueued.Dequeue();
                byte[] byteData = Encoding.ASCII.GetBytes(data);
                handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
            }

            //handler.Shutdown(SocketShutdown.Both);
            //handler.Close();
            setTimeoutTimer(false);
        }
        catch (Exception ex)
        {
            Console.WriteLine("!!! SERVER AcceptCallback");
            setTimeoutTimer(true);
        }
    }


    private void SendCallback(IAsyncResult ar)
    {
        try
        {
            ((Socket)ar.AsyncState).EndSend(ar);
        }
        catch(Exception ex)
        {
            Console.WriteLine("!!! SERVER SendCallback");
            setTimeoutTimer(true);
        }
    }      

}

Клиент:

    public class TCPclient : TCPunit
{
    private int    TIMEOUT_MS     = 5000;

    Socket     client;
    IPEndPoint remoteEP;        

    bool isConnecting = false;
    bool isRecieving  = false;  // TELS IF PROGRAM SHOULD LOOK FOR SERVER ALL TIME

    Action<string> afterRecieveAction = null ; // To print to GUI


    public TCPclient()
    {
        initTimeout(TIMEOUT_MS, reconnect);
    }



    public void assignAfterRecieveAction(Action<string> action)
    {
        this.afterRecieveAction = action;
    }

    public bool connect(string adress)
    {
        thisUnitAdress = adress;
        loopedConnect();
        return true;
    }
    public bool disconnect()
    {
        isRecieving = false;
        isConnecting = false;
        loopedDisconnect();
        return true;
    }

    private bool loopedConnect()
    {                              

        IPAddress ipAddress = IPAddress.Parse(this.thisUnitAdress);
        remoteEP = new IPEndPoint(ipAddress, port);

        client = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

        setTimeoutTimer(true);
        isRecieving = true;
        StartClientListening();
        return true;
    }

    private bool loopedDisconnect()
    {
        if (client != null)
        {             
            if (client.Connected) client.Shutdown(SocketShutdown.Both);
            client.Close();

            Console.WriteLine("CLIENT CLOSED!");
            client = null;
        }
        return true;
    }
    private void reconnect(Object source, System.Timers.ElapsedEventArgs e)
    {
        if (isRecieving)
        {
            Console.WriteLine("CLIENT RECONNECT!!!");
            if (isConnecting) loopedDisconnect();
            isRecieving = true;
            loopedConnect();
        }
    }

    private void StartClientListening()
    {
        try
        {
            if (isRecieving)
            {
                client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback) , client);
                isConnecting = true;
                Console.WriteLine("CLIENT listens to: " + thisUnitAdress + " port : " + port.ToString());
            }
        }
        catch (System.Net.Sockets.SocketException ex)
        {
            Console.WriteLine("CLIENT StartClientListening");

        }
        catch (Exception ex)
        {
            Console.WriteLine("!!! CLIENT StartClientListening2");
            if (isRecieving) setTimeoutTimer(true);
        }
    }


    private void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            client.EndConnect(ar);
            Console.WriteLine("CLIENT connected to {0}", client.RemoteEndPoint.ToString());
            StateObject state = new StateObject();
            state.workSocket = client;
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); ;
        }
        catch (Exception e)
        {              
            Console.WriteLine("!!! CLIENT ConnectCallback");
            if (isRecieving) setTimeoutTimer(true);
        }

    }


    private void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.workSocket;

            int bytesRead = client.EndReceive(ar);

            if (bytesRead > 0)
            {
                String response = Encoding.ASCII.GetString(state.buffer);
                if (afterRecieveAction != null) afterRecieveAction(response);
                resetTimeoutTimer();
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
            }                           
        }

        catch(System.Net.Sockets.SocketException ex)
        {
            Console.WriteLine("!!! CLIENT ReceiveCallback");
            if (isRecieving) setTimeoutTimer(true);
        }
        catch(Exception ex)
        {
            Console.WriteLine("!!! CLIENT ReceiveCallback2");
            if (isRecieving) setTimeoutTimer(true);
        }
    }

}

Как заставить работать async Server-Client без таймаутов?

С уважением, Крис

1 Ответ

0 голосов
/ 14 июня 2019

Вы должны использовать socket_set_option для параметризации этого

...