Как создать новый поток каждый раз, когда новое соединение получено в C #? - PullRequest
1 голос
/ 19 сентября 2011

Итак, я новичок в многопоточности и программировании сокетов, особенно в C #.

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

Вот что я сделал:

    public static void Listen()
    {
        try
        {
            listener = new TcpListener(IPAddress.Any, port);
            listener.Start();

            while (true)
            {
                t = new Thread((client = listener.AcceptTcpClient));

            }
        }
        catch { Listen(); }
    }

Я также уже объявил слушатель как TcpListener, t как поток и клиент как TcpClient.

Код в порядке, за исключением того, где я создаю поток, он выдает ошибку.

Моя конечная цель - создать новый поток для каждого принятого соединения, а затем иметь возможность отправлять данные определенному соединению.

Итак, как мне создать каждое соединение / клиент в новом потоке? Как я могу сослаться на определенный поток / соединение из другого метода, называемого Send (чтобы отправить данные через поток только в определенный поток / соединение)?

Ответы [ 4 ]

5 голосов
/ 19 сентября 2011

Поскольку вы упоминаете, что вы новичок в потоках и сокетах, я рекомендую изменить подходСоздание нового потока для каждого входящего соединения будет плохо масштабироваться.1000 пользователей приводят к 1000 потокам, и ваш сервер будет тратить большую часть своего времени на переключение контекста.Вместо этого вам следует рассмотреть возможность использования асинхронных методов ввода / вывода (например, TcpListener.BeginAcceptTcpClient ).Обратный вызов, который вы предоставляете этому методу, будет вызываться в потоке пула потоков .NET только тогда, когда требуется что-то сделать.Обязательно синхронизируйте доступ к переменным экземпляра (например, с помощью оператора блокировки), поскольку, если два клиента подключаются одновременно, обратные вызовы могут выполняться параллельно (что, конечно, является целью).Желаем удачи.

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

Конструктор Thread принимает делегата, пока вы пытаетесь дать ему объект. Когда вы создаете поток, вы должны предоставить метод, который будет выполняться в этом потоке. Например:

private void HandleClient(TcpClient client)
{
   // ... 
}

Однако создавать собственные темы обычно плохая идея. Вы должны использовать ThreadPool или Task Parallel Library, если вы используете .NET 4:

ThreadPool.QueueUserWorkItem(() => HandleClient(acceptedClient));

или

Task.Factory.StartNew(() => HandleClient(acceptedClient));
0 голосов
/ 19 сентября 2011

Это не очень хороший способ делать вещи. Вы должны взглянуть либо на шаблон BeginXXX / EndXXX, либо на шаблон Async для сокетов.

http://msdn.microsoft.com/en-us/library/bbx2eya8.aspx

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

Вот мой метод запуска для образца сокет-сервера, который у меня был.Обратите внимание, что новый поток принимает новый ThreadStart в качестве аргумента.Я могу прислать больше образца, если необходимо.

Он использует ThreadPool.QueueUserWorkitem вместо использования потока для запроса.Посмотрите на слушателя.

    public void Start()
    {
        m_protocol = LoadProtocolPlugIn();

        // Create a TcpListener to accept client connection requests
        TcpListener tcpListener = new TcpListener(m_address, m_port);
        tcpListener.Start();

        //
        // Create a protocol listener per thread
        //
        for (int i = 0; i < m_listeners; i++)
        {
            ProtocolListener listener = new ProtocolListener(tcpListener, m_protocol);
            Thread thread = new Thread(new ThreadStart(listener.Start));
            thread.Start();

            Console.WriteLine("Listening on thread: {0}", thread.Name);
        }

        m_state = ServerState.Started;
    }

и вот слушатель протокола:

class ProtocolListener
{
    TcpListener m_listener;
    IProtocol   m_protocol = null;
    TcpClient   m_client = null;

    internal ProtocolListener(TcpListener listener, IProtocol protocol)
    {
        m_listener = listener;
        m_protocol = protocol;
    }

    internal void Start()
    {
        //
        // Block waiting for socket connection and then process.  Repeat in endless loop.
        //
        while (true)
        {
            try
            {
                m_client = m_listener.AcceptTcpClient();
                ThreadPool.QueueUserWorkItem (new WaitCallback(ProcessClientProtocol), m_protocol);
            }
            catch (SocketException se)
            {
                // TODO: replace with logging and event log
                Console.WriteLine("Exception = " +  se.Message);
            }
        }
    }

    private void ProcessClientProtocol (object protocol)
    {
        Debug.Assert(m_client != null);
        Debug.Assert(protocol != null);

        ((IProtocol)protocol).Client = m_client;
        ((IProtocol)protocol).ProcessClient();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...