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

时间:2013-01-22 10:12:52

标签: c sockets epoll sctp epollet

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

步骤:

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

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

1 个答案:

答案 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()以确保您不会丢失任何数据。 (同样为了进入发送状态,尝试初始发送)。