Помощь с управляемым событиями TCP-сервером - PullRequest
6 голосов
/ 16 марта 2011

Я работаю над «системой приложений», где мне также нужно создать серверное приложение.Я работаю в C # (.NET 4.0).Сервер будет в основном собирать данные из разных приложений / клиентов POS (которые должны быть около 50-100, но сервер должен быть способен обрабатывать также около 200-300 клиентов).С одного клиента сервер, вероятно, будет получать около 1 КБ около 100 раз в день.Сервер в основном должен принять данные, расшифровать их и сохранить на диск.Он также должен проверять изменения в определенном каталоге для отправки новых конфигураций клиентам, что не должно быть очень часто.

Я довольно новичок в C # и программировании сервера, поэтому, пожалуйста, потерпите меня.Я подумал об использовании потоковых и асинхронных методов (есть хороший пример использования этого в книге "C # в двух словах").Но я провожу довольно много времени в поисках лучшего решения, и я нашел это.Но многопоточность в моем случае приносит больше проблем, чем пользы.Таким образом, я думал о даже управляемом сервере.«Единый процесс, обрабатывающий каждое событие (принятое соединение, данные, доступные для чтения, запись в клиент, ...) при обратном вызове».из " что такое управляемый событиями веб-сервер ".Я считаю, что это лучшее решение моей проблемы.

Но я понятия не имею, как его кодировать, я не смог найти примеров о серверах, управляемых событиями.Насколько я понимаю, я должен создать один поток (+ 1 для GUI), затем создать прослушиватель TCP и затем каким-то образом создать события, чтобы, когда прослушиватель TCP мог принять клиента, событие вызывало и вызывало сервер, также когда данныечтение из клиентов было бы доступно, это разбудило бы сервер.

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

while(true)
{
   check if client wants to connect
        accept client and add it to client list
   iterate through client list and check if anyone is sending data ...
        accept data and store it
   ...
  }

Но это не связано с событиями и тратит процессор.Сервер не будет очень активным, поэтому я хотел бы сделать его максимально эффективным.

Некоторые примеры действительно помогут.

Спасибо за ваше время и ответы.

ps Могу ли я использовать только один порт для всех клиентов?

РЕДАКТИРОВАТЬ: Чтобы уточнить, я хочу кодировать сервер, управляемый событиями, но я не знаю, как, таким образом,Я только что привел пример того, что я знаю (опрос клиентов).

Ответы [ 6 ]

3 голосов
/ 16 марта 2011

Во-первых, если вы новичок в C # и многопоточности и сокетах, то это lot , чтобы оторваться для вашего первого проекта. Я рекомендую изучать их индивидуально.

Тем не менее, вы можете найти Nito.Async.Sockets полезными; он включает в себя управляемый событиями серверный сокет и решает проблемы многопоточности для вас.

1 голос
/ 16 марта 2011

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

class Program
{
    public static ManualResetEvent connected = new ManualResetEvent(false);

    static void Main(string[] args)
    {
        string ip = "127.0.0.1";
        int port = 14500;

        TcpListener server = new TcpListener(IPAddress.Parse(ip), port);
        server.Start();

        Console.WriteLine("Server started...");

        while (true)
        {
            connected.Reset();
            server.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), server);
            connected.WaitOne();
        }
    }

    public static void AcceptCallback(IAsyncResult ar)
    {
        TcpListener listener = (TcpListener)ar.AsyncState;
        TcpClient client = listener.EndAcceptTcpClient(ar);

        byte[] buffer = new byte[1024];
        NetworkStream ns = client.GetStream();
        if (ns.CanRead)
        {
            ns.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), new object[] { ns, buffer });
        }

        connected.Set();
    }

    public static void ReadCallback(IAsyncResult ar)
    {
        NetworkStream ns = (NetworkStream)((ar.AsyncState as object[])[0]);
        byte[] buffer = (byte[])((ar.AsyncState as object[])[1]);
        int n = ns.EndRead(ar);
        if (n > 0)
        {
            Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, n));
        }
        ns.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), new object[] { ns, buffer });
    }
}
1 голос
/ 16 марта 2011

Событие, управляемое событиями, точно не описывает, как вы ожидаете, что ваша система будет работать, потому что вы описываете опрос ваших клиентов на предмет обработки данных вместо того, чтобы ваши клиенты отправляли свои данные в вашу службу (вызывая событие).

Если у вас очень мало идей о том, как кодировать такую ​​систему, вы могли бы изучить существующие решения / продукты для вашего сценария.

Я бы порекомендовал проверить такие инструменты EAI, как BlueIntegrator или BizTalk для интеграции POS-клиентов.

Для вашего требования относительно развертывания обновлений клиента вы можете посмотреть BITS .

1 голос
/ 16 марта 2011

Я бы предложил использовать WCF в качестве службы Windows, которая обеспечивает масштабируемую и многопоточную платформу. Он также может быть адаптирован в соответствии с требованиями протокола. Вот пример, который можно использовать в качестве ссылки:

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

1 голос
/ 16 марта 2011

Я не знаю, что такое фреймворки C #, но вы можете взглянуть на Twisted , фреймворк Python, управляемый событиями.Вы можете найти примеры кода серверов и клиентов, аналогичные вашим потребностям.

Вот пример очень простого сервера, который возвращает клиенту все, что он получил от него:

#!/usr/bin/env python

# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
# See LICENSE for details.

from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor

### Protocol Implementation

# This is just about the simplest possible protocol
class Echo(Protocol):
    def dataReceived(self, data):
        """
        As soon as any data is received, write it back.
        """
        self.transport.write(data)


def main():
    f = Factory()
    f.protocol = Echo
    reactor.listenTCP(8000, f)
    reactor.run()

if __name__ == '__main__':
    main()

Относительно вашего последнего вопроса:

PS Могу ли я использовать только один порт для всех клиентов?

Да, вы можете (на каком языке / фреймворке вы используете).

0 голосов
/ 24 апреля 2012

Я немного опоздал на вечеринку, но недавно я начал новую работу по разработке программного обеспечения для интеграции с научными инструментами, и в настоящее время испытываю трудности с изучением потоков, коммуникаций, асинхронной обработки и т. Д. Threading в C # Джо Албахари - отличный ресурс для изучения потоковой стороны.

...