Несколько потоков в одном сокете TCP - PullRequest
0 голосов
/ 16 сентября 2011

Я разработчик .NET и новичок в программировании на сокете.

Я написал программу, которая отправляет некоторые данные клиенту с помощью сокета TCP с использованием библиотеки сокетов .NET.

Клиенту требуется настраиваемое сообщение Keep Alive Message каждые 40 секунд, чтобы поддерживать соединение.

Итак, я написал основную программу, которая устанавливает связь с клиентом. В этой основной программе я создаю поток и передаю экземпляр класса Socket, который был создан ранее. Этот поток отвечает за отправку сообщений поддержки активности клиенту, в то время как основной поток отвечает за отправку данных.

Все работает хорошо. Но если по какой-то причине время подключения сокета истекло, программа никогда не восстановится? Я установил логику для выхода из обоих потоков и установления нового соединения, но оно всегда выдаст ошибку - «Соединение с хостом прервано» или что-то подобное.

Я что-то не так делаю?

Мне нужно, чтобы два потока были подключены к одному сокету. Один поток отвечает за отправку данных, а другой - за отправку сообщений поддержки активности. Какой подход должен быть лучшим для этого?

Нет, я не пытаюсь использовать один и тот же сокет. Я отрываюсь от цикла for и clntSock.close () ...

Вот код:

У меня есть mainThread, который вызывает handleClient. handleClient Создает другой поток.

class DispatchLoop
{
    ILogger logger;
    TcpListener listener;
    IProtocolFactory protoFactory;

    public DispatchLoop(TcpListener listener, ILogger logger, IProtocolFactory protoFactory)
    {
        this.logger = logger;
        this.listener = listener;
        this.protoFactory = protoFactory;
    }

    public void mainThread()
    {
        // Run forever, accepting and handling each connection
        for (; ; )
        {
            try
            {
                Socket clntSock = listener.AcceptSocket(); // Block waiting for connection
                PoolDispatcher._stopper.Reset();
                clntSock.ReceiveTimeout = 10000;
                IProtocol protocol = protoFactory.createProtocol(clntSock, logger);
                protocol.handleClient();
            }
            catch (SocketException se)
            {
                logger.writeEntry("(Run Dispatcher) Exception = " + se.Message);
            }
        }
    }
}

    public void handleClient()
    {
        entry.Add("Main Thread Entered : Client address and Port = " + clntSock.RemoteEndPoint + ", Thread Number = " + Thread.CurrentThread.GetHashCode());

        //Kick Starting Keep Alive Thread
        KeepAlive ka = new KeepAlive(clntSock, logger);
        Thread thread = new Thread(new ThreadStart(ka.SendKeepAlive));
        thread.Start();
        try
        {
            int recvMsgSize; // Size of received message
            byte[] rcvBuffer = new byte[BUFSIZE]; // Receive buffer
            byte[] messageBuffer = new byte[1024];
            XDocument _messageXDoc;
            FlightInfoExtended _flightInfoExtended;
            try
            {
                LogEntry(entry);
                for (; ; )
                {
                    try
                    {
                        //Read from the Queue 
                        var _queue = new IBMQueue();
                        var message = _queue.ReceiveMessage();

                        if (message.Length > 0)
                        {
                            entry.Add("Sending the GOS Message to the client : " + message);
                            messageBuffer = Encoding.ASCII.GetBytes(message);

                            if (clntSock.Connected)
                            {
                                clntSock.Send(messageBuffer, 0, messageBuffer.Length, SocketFlags.None);
                                recvMsgSize = clntSock.Receive(rcvBuffer, 0, rcvBuffer.Length, SocketFlags.None);
                                SaveGOSMessage(_auditMessage);
                            }
                            else
                            {
                                PoolDispatcher._stopper.Set();
                                LogFailureStatus("No Socket Connection");
                                Thread.Sleep(30000);
                                break;
                            }
                        }
                    }
                    catch (SocketException se)
                    {
                        PoolDispatcher._stopper.Set();
                        LogFailureStatus(se.Message);
                        Thread.Sleep(30000);
                        break;
                    }
                    catch (Exception e)
                    {
                    }
                    LogEntry(entry);
                }
            }
            catch (Exception se)
            {
                entry.Add(String.Format("{0}: {1}", se.Source, se.Message));
            }
        }
        catch (Exception se)
        {
            entry.Add(String.Format("{0}: {1}", se.Source, se.Message));
        }

        clntSock.Close();

        logger.writeEntry(entry);
    }



public class KeepAlive
{
    ArrayList entry;
    private ILogger logger;
    private Socket clntSock;
    public const int BUFSIZE = 1024;

    public KeepAlive(Socket clntSock, ILogger logger)
    {
        this.logger = logger;
        this.clntSock = clntSock;
        entry = new ArrayList();
    }

    void LogEntry(ArrayList _entry)
    {
        logger.writeEntry(_entry);
        entry.Clear();
    }

    public void SendKeepAlive()
    {
        entry.Add("Keep Alive Thread Entered : Client address and Port = " + clntSock.RemoteEndPoint + ", Thread Number = " + Thread.CurrentThread.GetHashCode());

        var message= "Some Keep Alive Message";

        try
        {
            byte[] messageBuffer = new byte[1024];
            LogEntry(entry);
            for (; ; )
            {
                //Check if main thread died
                if ( PoolDispatcher._stopper.WaitOne(100, false))  
                {                                 
                    break;
                }

                if (clntSock.Connected)
                {
                    entry.Add("Sending the Keep Alive Message... " + message);
                    messageBuffer = Encoding.ASCII.GetBytes(message);
                    clntSock.Send(messageBuffer, 0, messageBuffer.Length, SocketFlags.None);
                }
                else
                {
                    entry.Add("Socket Connection is not active. Keep Alive not sent");
                    break;
                }
                LogEntry(entry);
                Thread.Sleep(30000);
            }
        }
        catch (SocketException se)
        {
            entry.Add(String.Format("{0}: {1}", se.ErrorCode, se.Message));
        }
        catch (ObjectDisposedException ode)
        {
            entry.Add("Connection to the socket lost. Child Thread Aborted");
        }
        LogEntry(entry);
    }
}

1 Ответ

0 голосов
/ 17 сентября 2011

Это просто сделать, просто интегрируя два модуля .ie server и Client в один поток и порождая поток чтения-записи для каждого экземпляра, для каждого Socket с IP-адресом (не с тем же портом)

http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient%28v=VS.90%29.aspx & http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener%28v=VS.90%29.aspx

используйте только это, оно отлично работает.Я закончил эту вещь, надеюсь, это поможет вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...