多个线程到同一个TCP套接字

时间:2011-09-16 01:34:31

标签: c# .net multithreading sockets

我是.NET开发人员,是Socket Programming的新手。

我编写了一个程序,它使用.NET套接字库使用TCP套接字将一些数据发送到客户端。

客户端需要每40秒自定一次保持活动消息以保持连接活动。

所以,我编写了与客户建立连接的主程序。在这个主程序中,我创建了一个线程并传递了之前创建的Socket类的实例。该线程负责在主线程负责发送数据时向客户端发送保持活动消息。

这一切都很好。但如果由于某种原因套接字连接超时,程序将永远无法恢复?我把两个线程的逻辑都退出并建立了新的连接,但它总是会出错 - '与主机的连接中止'或者类似的东西。

我做错了吗?

我需要将两个线程连接到同一个套接字。一个线程负责发送数据,另一个线程负责发送保持活动消息。对此最好的方法是什么?

不,我不是想尝试使用相同的套接字。我脱离了for循环和clntSock.close()......

以下是代码:

我有调用handleClient的mainThread。 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 :(得分:0)

它易于实现只需将两个模块.i.e服务器和客户端集成在单个线程中,并为每个实例生成读写线程,每个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

单独使用它可以完美运行。 我完成了这件事,希望它可以帮助你。