繁体   English   中英

C:使用epoll ET的数据转发服务器填充发送缓冲区

[英]C: Data forwarding server using epoll ET fills the send buffer

我有以下情况。 我的服务器从远程服务器(fd_server)接收数据,并将其转发到客户端(fd_client)。 我正在使用边缘触发的epoll,以便可以处理多个客户端和多个服务器连接。

程序:

  1. 客户端连接到服务器。
  2. 我的服务器连接到远程服务器并请求数据。
  3. 远程服务器响应,我的服务器将数据转发到客户端。

细节:

我的服务器连接到远程服务器后,将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;}
    }
}

经过一些读/写后,我的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()只是为了确保您不会丢失任何数据。 (类似地,要进入发送状态,请尝试初始发送)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM