我有以下情况。我的服务器从远程服务器(fd_server)接收数据并将其转发到客户端(fd_client)。我正在使用边缘触发的epoll,因此我可以处理多个客户端和多个服务器连接。
步骤:
详细说明:
我的服务器连接到远程服务器后,fd_server被添加到带有EPOLLIN标志的epoll控件。服务器等待事件。
当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;}
}
}
答案 0 :(得分:0)
经过一些读/写后,我的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)
};
如果您无法一次发送所有内容,请在epoll模式下将fd_client套接字从EPOLLIN切换到EPOLLOUT。在ConnectionState结构中将“has_data”更改为true。然后返回等待套接字事件。当您能够再次发送时,您可以查看该套接字的ConnectionState结构,以确定是否仍需要继续发送或接收新缓冲区。
小心边缘触发的套接字。当您从EPOLLOUT转换回EPOLLIN时,您需要继续并再次recv()以确保您不会丢失任何数据。 (同样为了进入发送状态,尝试初始发送)。