C: Сервер пересылки данных с помощью epoll ET заполняет буфер отправки
У меня следующая ситуация. Мой сервер получает данные с удаленного сервера (fd_server) и пересылает их клиенту (fd_client). Я использую краевой epoll, чтобы я мог обрабатывать несколько клиентов и несколько серверных конфликтов.
Процедура:
- клиент подключается к серверу.
- мой сервер подключается к удаленному серверу и запрашивает данные.
- удаленный сервер отвечает, и мой сервер передает данные клиенту.
Подробности:
После того, как мой сервер подключится к удаленному серверу, сервер 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(), чтобы убедиться, что вы не потеряете данные. (Аналогично для входа в состояние отправки попробуйте начальную отправку).