вопрос о розетках - PullRequest
0 голосов
/ 13 ноября 2010

У меня есть классы сервера и клиента, но проблема в том, что когда я делаю бесконечный цикл для принятия входящего соединения, я не могу получить все данные, полученные от клиента, принимая соединения, потому что принимаю блоки, пока соединение не будет принято, мой код:

    for (;;) 
    {
       boost::thread thread(boost::bind(&Irc::Server::startAccept, &s));
       thread.join();
       for (ClientsMap::const_iterator it = s.begin(); it != s.end(); ++it) 
       {
          std::string msg = getData(it->second->recv());
          std::clog << "Msg: " << msg << std::endl;
       }
    }

Ответы [ 3 ]

3 голосов
/ 13 ноября 2010

Вам нужно либо несколько потоков, либо вызов select / poll, чтобы узнать, какие соединения имеют необработанные данные. У IBM есть хороший пример здесь , который будет работать на любом варианте Unix, Linux, BSD и т. Д. (Вам могут потребоваться разные заголовочные файлы в зависимости от ОС).

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

0 голосов
/ 13 ноября 2010

Посмотрите здесь: http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/examples.html

особенно пример HTTP Server 3 , это именно то, что вы ищете, все что вам нужно сделать, это немного изменить этот коддля ваших нужд :) и готово

0 голосов
/ 13 ноября 2010

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

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

Если вы не хотите создавать новый поток для каждого подключенного клиента, тогда, как предложил Бен Фойгт, вы можете использовать select.Это еще один хороший подход, если вы хотите сделать его однопоточным.По сути, все ваши сокеты будут в массиве дескрипторов сокетов, и, используя select, вы будете знать, что произошло (кто-то подключен, сокет готов к чтению / записи, сокет отключен и т. Д.) И будете действовать соответственно.

Вот одинПример частичный, но работает.вы просто принимаете соединения в acceptConnections (), который затем создает отдельный поток для каждого клиента.Вот где вы общаетесь с клиентами.Это из кода Windows, который я лежал без дела, но его очень легко переопределить для любой платформы.

typedef struct SOCKET_DATA_ {
  SOCKET sd;
  /* other parameters that you may want to pass to the clientProc */
} SOCKET_DATA;

/* In this function you communicate with the clients */
DWORD WINAPI clientProc(void * param)
{
    SOCKET_DATA * pSocketData = (SOCKET_DATA *)param;

    /* Communicate with the new client, and at the end deallocate the memory for
       SOCKET_DATA and return.
    */

    delete pSocketData;
    return 0;
}

int acceptConnections(const char * pcAddress, int nPort)
{
    sockaddr_in sinRemote;
    int nAddrSize;
    SOCKET sd_client;
    SOCKET sd_listener;
    sockaddr_in sinInterface;
    SOCKET_DATA * pSocketData;
    HANDLE hThread;

    sd_listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (INVALID_SOCKET == sd_listener) {
        fprintf(stderr, "Could not get a listener socket!\n");
        return 1;
    }

    sinInterface.sin_family = AF_INET;
    sinInterface.sin_port = nPort;
    sinInterface.sin_addr.S_un.S_addr = INADDR_ANY;

    if (SOCKET_ERROR != bind(sd_listener, (sockaddr*)&sinInterface, sizeof(sockaddr_in))) {
        listen(sd_listener, SOMAXCONN);
    } else {
        fprintf(stderr, "Could not bind the listening socket!\n");
        return 1;
    }

    while (1)
    {
        nAddrSize = sizeof(sinRemote);
        sd_client = accept(sd_listener, (sockaddr*)&sinRemote, &nAddrSize);

        if (INVALID_SOCKET == sd_client) {
            fprintf(stdout, "Accept failed!\n");
            closesocket(sd_listener);
            return 1;
        }

        fprintf(stdout, "Accepted connection from %s:%u.\n", inet_ntoa(sinRemote.sin_addr), ntohs(sinRemote.sin_port));
        pSocketData = (SOCKET_DATA *)malloc(sizeof(SOCKET_DATA));

        if (!pSocketData) {
            fprintf(stderr, "Could not allocate memory for SOCKET_DATA!\n");
            return 1;
        }

        pSocketData->sd = sd_client;
        hThread = CreateThread(0, 0, clientProc, pSocketData, 0, &nThreadID);

        if (hThread == INVALID_HANDLE_VALUE) {
            fprintf(stderr, "An error occured while trying to create a thread!\n");
            delete pSocketData;
            return 1;
        }
    }

    closesocket(sd_listener);
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...