清空socket接收队列

本文介绍了在Linux内核中如何清空socket的接收缓冲区。通过setsockopt函数设置SO_RCVBUF选项调整缓冲区大小,并利用select函数配合recvfrom清空已接收的数据,从而确保获取最新消息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在socket建立时,linux的内核会为socket分配一个发送缓冲区和一个接收缓冲区,实际上是一个struct sk_buff的队列,当我们调用send/sendto/sendmsg及recv/recvfrom/recvmsg时,会发送或接收队列中的第一个数据。

现在我们只考虑接收的情况,如果甲一直不停的向乙发送消息,而乙中每次调用recv/recvfrom/recvmsg都想得到最新的数据,怎么办?

这就需要我们对linux的缓冲区进行清空。而缓冲区是在内核中的,不允许直接操作。还好,有两个函数可以解决这个问题。

第一个是int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len), 他是对

socket的设置。我们可以通过它修改接收缓冲区的大小。他还有很多功能,见man setsockopt.

   int lLen, lRet

   lRet = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &lLen, sizeof(int));

   sock就是我们创建的socket 的描述符。

   如果对linux内核代码进行研究,会发现lLen不是设置成所有的值都有效。

  if (val > sysctl_rmem_max)
                val = sysctl_rmem_max;
set_rcvbuf:
            sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
            /* FIXME: is this lower bound the right one? */
            if ((val * 2) < SOCK_MIN_RCVBUF)
                sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
            else
                sk->sk_rcvbuf = val * 2;
            break;

    也就说,他有一个最大值和一个最小值。 最大值是262144, 最小值是256。

 

 

     我们在看一下内核中缓冲区分配的函数

     ...
      size = SKB_DATA_ALIGN(size);
      ...
      skb->truesize = size + sizeof(struct sk_buff);

 

     在sock_queue_rcv_skb函数中有
       if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
        (unsigned)sk->sk_rcvbuf) {
        err = -ENOMEM;
        goto out;
      }

 

      这样,当接收到一个数据包后,内核缓冲区会分配size + sizeof(struct sk_buff)大小的缓冲区,其中size是cache line对齐的。

也就是说,只有我们设置的缓冲区大于这个值,数据才会到用户空间。

 

 

       好了,我们设置了接收区的大小以后,缓冲区中只有一个数据包,可以用select函数进行清空。

  struct timeval stWait;
      fd_set         stFdSet;
      int            lRet;
     
      stWait.tv_sec = 0;
      stWait.tv_usec = 0;
      while(1)
      {
           FD_ZEROS(&stFdSet);
           FD_SET(g_lSock, &stFdSet);
           lRet = select(FD_SETSIZE, &stFdSet, NULL, NULL, &stWait);
           if(lRet == 0)
                  break;
           recvfrom(g_lSock, cBuf, sizeof(cBuf), 0, (struct sockaddr *)tClient, &lLen);
      }
     
      然后再调用recvfrom接收最新的消息。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值