2014-02-21 4 views
0

У меня, похоже, проблема с увеличением задержки при передаче пакетов с моего TCP-сервера. Теперь этот сервер должен быть TCP, поскольку UDP блокируется брандмауэрами (это тип связи клиент-сервер-клиент). Я также знаю, что отправка структуры с целыми числами с плавающей запятой, как я, крайне не переносима, однако в обозримом будущем эта система будет работать с клиентом Windows на сервер Windows на клиент Windows.C++ TCP Socket Exponential Увеличивающая задержка

Проблема заключается в следующем: клиент начинает получать данные должным образом от другого клиента, однако есть задержка, которая экспоненциально ухудшается (где примерно на 3 минуты пакеты отстают почти на 30 секунд, но правильно , когда они ДОЛЖНЫ прибыть). Я исследовал его и нашел ответ на странице Microsoft, объясняющий, что это связано с полными буферами отправки, однако их синтаксис для setsockopt не соответствует документированным примерам, поэтому, возможно, я ошибаюсь.

Во всяком случае, любые советы будут оценены:

Соответствующая часть сервера:

(Если принять() называется :)

int buff_size = 2048000; 
int nodel = 1; 
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&buff_size, sizeof(int)); 
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&buff_size, sizeof(int)); 
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&nodel, sizeof(nodel)); 

сообщение перенаправления цикл:

if (gp->curr_pilot < sz && gp->users[gp->curr_pilot].pilot == TRUE) { 
      char* pbuf = new char[1024]; 
      int recvd = recv(gp->users[gp->curr_pilot].sockfd_data, pbuf, 1024, NULL); 
      if (recvd > 0) { 
       for (int i = 0; i < sz; i++) { 
        if (i != gp->curr_pilot && gp->users[i].unioned == TRUE) 
         send(gp->users[i].sockfd_data, pbuf, recvd, NULL); 
       } 
      } 
      delete[] pbuf; 
     } 

Клиент (мастер устанавливается, когда он отправляется, и он правильно устанавливается на m y code):

(данные - это моя структура удвоений, которая записывается клиентом, cdata - это копия, которая записывается в клиент).

while (kill_dataproc == FALSE) { 
    if (master == TRUE) { 
     char* buff = new char[1024]; 
     int packet_signer = 1192; 
     memcpy_s(buff, intsz, &packet_signer, intsz); 
     memcpy_s((void*)(buff + intsz), sz, data, sz); 
     send(server_sock, buff, buffsize, NULL); 
     delete[] buff; 
    } 
    else {   
     char* buffer = new char[1024]; 
     int recvd = recv(server_sock, buffer, 1024, MSG_PEEK); 
     if (recvd > 0) { 
      int newpacketsigner = 0; 
      memcpy_s(&newpacketsigner, intsz, buffer, intsz); 

      if (newpacketsigner == 1192) { 
       if (recvd >= buffsize) { 
        char* nbuf = new char[buffsize]; 
        int recvd2 = recv(server_sock, nbuf, buffsize, NULL); 
        int err = WSAGetLastError(); 

        memcpy_s(&newpacketsigner, intsz, nbuf, intsz); 
        memcpy_s(cdata, sz, (void*)(nbuf + intsz), sz); 
        //do things w/ the struct      
        delete[] nbuf;      
       } 
      } 
      else     
       recv(server_sock, buffer, 1024, NULL); 
     } 
     delete[] buffer; 
    } 

    Sleep(10); 
} 

Как одинаковые вызовы setsockopt и называются сокетами клиента, и все розетки, сервер и клиент, являются блокирующими.

+0

Я бы рекомендовал упростить вашу программу, пока проблема не исчезнет (тогда причина, вероятно, то, что вы удалили), или она проста и достаточно для понимания другими. Вы можете попробовать начать с удаления Sleep (10), который выглядит подозрительным для меня. –

+0

Sleep (10) - это предотвращение того, чтобы этот цикл сосал 100% использования ЦП в системе клиента. –

+0

Если вам нужно спать, чтобы не сосать CPU, вы делаете неблокирующий ввод-вывод полностью неправильным (вы сказали, что сокеты не блокируются). –

ответ

0

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

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

NB Буферы, принимающие буферы, больше 64k и поэтому могут быть неработоспособными, если они не установлены до того, как сокет подключен. В случае сервера вам необходимо установить размер буфера приема в прослушивающем сокете. Принятые сокеты наследуют его. Если вы этого не сделаете, масштабирование окна не будет действовать, поэтому окно> 64k не может быть объявлено (если платформа по умолчанию не имеет окна).

+0

Я зацикливаюсь - он получает что-то, если он не распознается, он отбрасывает его, иначе он его использует. –

+0

Вы зацикливаете, но нигде вы не гарантируете, что вы получили 1024 байта или независимо от вашего размера буфера, или размер вашего сообщения. Вы просто делаете довольно случайные вызовы 'recv()'. Ваш код в принципе не работает вообще. – EJP