Локальная обратная связь в Winsock - PullRequest
4 голосов
/ 12 октября 2010

Я использую сокеты tcp для обеспечения межпроцессного взаимодействия между двумя приложениями в Windows XP.Я выбрал сокеты tcp по разным причинам.Я вижу среднее время приема-передачи 2,8 мс.Это намного медленнее, чем я ожидал.По-видимому, профилирование показывает, что задержка между отправкой вызова одним приложением и возвратом блокировки блокировки другого конца.

У меня тоже есть приложения, демон и клиент.Они структурированы так: псевдокод:

Поток демона 1 (прослушивает новые подключения):

while (1) {
   SOCKET listener_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   bind(listener_socket, (SOCKADDR*)&server_info, sizeof(SOCKADDR));
   listen(listener_socket, 1);
   SOCKET client_socket = accept(listener_socket, NULL, NULL);
   closesocket(listener_socket);
   CreateThread(client_thread);
 }

Поток демона client_socket (прослушивает пакеты от клиента):

char cmdBuf[256];
int cmdBufAmountData = 0;

while (1)
{   
    char recvBuf[128];
    int bytesTransferred = recv(m_clientSocket, recvBuf, sizeof(recvBuf), 0);

    // Copy received data into our accumulated command buffer (commands 
    // may be split across packet boundaries)
    memcpy(cmdBuf + cmdBufAmountData, recvBuf, bytesTransferred);
    cmdBufAmountData += bytesTransferred;

    // See if there is one or more complete commands in cmdBuf 
    // (commands are separated by '\0')
    while (commandExists(cmdBuf, cmdBufAmountData))
    {
        // do stuff with command
        send(m_clientSocket, outBuf, msgLen, 0);

        // Throw away the command we just processed by shuffling 
        // the contents of the command buffer left
        for (int i = 0; i < cmdBufAmountData - cmdLen; i++)
            cmdBuf[i] = cmdBuf[i + cmdLen];
        cmdBufAmountData -= cmdLen;
    }
}

Клиентский поток 1:

start_timer();
send(foo);
recv(barBuf);
end_timer();       // Timer shows values from 0.7ms to 17ms. Average 2.8ms.

Есть идеи, почему задержка такая плохая?Я подозревал алгоритм Нагеля, но засоряя мой код:

BOOL bOptVal = TRUE;
setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&bOptVal, sizeof(BOOL));

Не помогает.Нужно ли делать это на сокетах клиента и демона (я так делаю)?

Я работаю на четырехъядерном компьютере почти без нагрузки, без активности диска и т. Д.

Ответы [ 2 ]

2 голосов
/ 12 октября 2010

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

SOCKET listener_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(listener_socket, (SOCKADDR*)&server_info, sizeof(SOCKADDR));
listen(listener_socket, 1);
while (1) {
   SOCKET client_socket = accept(listener_socket, NULL, NULL);
   closesocket(listener_socket);
   CreateThread(client_thread);
 }

Далее, да, если вы хотите отключить nagle, вам нужно сделать это как на принятом серверном сокете, так и на подключенном клиентском сокете. Вы можете сделать это сразу после подключения / принятия. Так что, если вы устанавливаете nagle только на один сокет, то это может быть вашей проблемой.

Учитывая, что вы используете TCP, я предполагаю, что вы читаете, пока не получите полное сообщение, и не предполагаете, что один отправляет на одной стороне == один на другой. (т.е. я предполагаю, что ваш код сокращен и не показывает нормальный цикл recv).

Сколько клиентов? Сколько потоков?

1 голос
/ 13 октября 2010

И вы не должны закрывать сокет прослушивания, пока не захотите выйти из своего сервера.

Я бы посмотрел на именованные каналы, а не на сокеты, если вы не возражаете против подключения к Windows API.

...