C: Сервер пересылки данных с помощью epoll ET заполняет буфер отправки

У меня следующая ситуация. Мой сервер получает данные с удаленного сервера (fd_server) и пересылает их клиенту (fd_client). Я использую краевой epoll, чтобы я мог обрабатывать несколько клиентов и несколько серверных конфликтов.

Процедура:

  1. клиент подключается к серверу.
  2. мой сервер подключается к удаленному серверу и запрашивает данные.
  3. удаленный сервер отвечает, и мой сервер передает данные клиенту.

Подробности:

После того, как мой сервер подключится к удаленному серверу, сервер fd_server будет добавлен в управление epoll с флагом EPOLLIN. Сервер ждет событий.

Когда epoll_wait возвращает fd_server как читабельный, я иду в следующем цикле, показанном ниже.

После некоторого чтения / записи мой sctp_sendmsg возвращает EAGAIN, что означает, что буфер отправки sctp заполнен. Как мне справиться с этой ситуацией, не теряя данные, которые я уже прочитал из сокета fd_server?

Есть ли способ узнать заранее, сколько данных я могу отправить, чтобы я прочитал только правильное количество?

while(1){
    N = recv(fd_server,buf, sizeof buf,0);
    if (N == -1){
      /* If errno == EAGAIN, that means we have read all
         data. So go back to the main loop. */
      if (errno != EAGAIN){
          perror ("tcp_recv error");

        }
      break;
    }
    if(N == 0){
      /* End of file. The remote has closed the
         connection. */
         close(fd_server);      
         break;
    }
    pos = 0;
    while(pos < N){
        got = sctp_sendmsg(fd_client, &buf[pos], N-pos, to, tolen, 0, 0, stream, 0, 0);

        if(got<=0){
            if (errno == EAGAIN){
                //what to do?
            }else{
                perror("tcp to sctp send error");
            }
        }
        else{
        pos += got;}
    }
}

1 ответ

После некоторого чтения / записи мой sctp_sendmsg возвращает EAGAIN, что означает, что буфер отправки sctp заполнен. Как мне справиться с этой ситуацией, не теряя данные, которые я уже прочитал из сокета fd_server?

Вам нужно сохранить своего рода "контекст" (структуру данных) для каждого сокета fd_client. Для каждого нового клиентского сокета, который подключается к вашему серверу, создайте экземпляр структуры "состояние соединения" и сохраните его в хеш-таблице. Это будет что-то вроде следующего:

struct ConnectionState
{
    int fd_client; // socket
    uint8_t buffer[MAX_CHUNK_SIZE];  // protocol buffer for this connection
    int buffer_length; // how many bytes received into this buffer
    int pos;           // how many bytes transmitted back out on fd_client from "buffer"
    int has_data;      // boolean to indicate protocol state (1 if there's still data in buffer to send)
};

Если вы не можете отправить все сразу, переключите сокет fd_client из EPOLLIN в EPOLLOUT в вашем режиме epoll. Измените "has_data" на true в структуре ConnectionState. Затем вернитесь к ожиданию событий сокета. Когда вы снова можете отправить, вы просматриваете структуру ConnectionState для этого сокета, чтобы решить, нужно ли вам продолжать отправлять или получать новый буфер.

Будьте осторожны с торцевыми розетками. Когда вы переходите от EPOLLOUT обратно к EPOLLIN, вам нужно снова выполнить recv(), чтобы убедиться, что вы не потеряете данные. (Аналогично для входа в состояние отправки попробуйте начальную отправку).

Другие вопросы по тегам