socket收包函数 buffer大小的设置

Ip_ssize_t recv(Ip_fd sock, void *buf, Ip_size_t len, int flags);

Ip_ssize_t  recvfrom(Ip_fd fd, void *buf, Ip_size_t len, int flags,struct Ip_sockaddr *from, Ip_socklen_t *fromlen);

这个buf大小需要考虑啥,有啥讲究吗?

 

1)  先来看看着实现代码(代码源自ipnet):

IP_GLOBAL int
ipnet_sock_pkt_recv(Ipnet_socket *sock, struct Ip_msghdr *msg, int flags)
{
    Ipcom_pkt *pkt;
    int        pkt_offset;
    int        buf_len;
    Ip_u8     *buf;
    int        bytes;
    Ip_size_t  i;
    int        read_bytes;

    // 获得socket recv队列里的第一个pkt

    bytes = ipnet_krecvfrom(sock, flags, msg->msg_name, &msg->msg_namelen, &pkt);
    if (bytes < 0)
        return bytes;

    if (msg->msg_control != IP_NULL)
        ipnet_add_ancillary_data(msg, sock, pkt);

    pkt_offset = pkt->start;
    for (bytes = 0, i = 0; i < msg->msg_iovlen && pkt_offset < pkt->end; i++)
    {
        buf = (Ip_u8 *) msg->msg_iov[i].iov_base;
        buf_len = msg->msg_iov[i].iov_len;

        /* Copy over minimum of bytes requested and available, i.e. truncation is ok. */

         // 比较buffer和pkt的大小,read_bytes值取较小的
        read_bytes = IP_MIN(buf_len, (int) pkt->end - pkt_offset);

        if (read_bytes > 0)
        {

            // 拷贝数据到用户缓存区buffer
            ipcom_copy_to_user(buf, &pkt->data[pkt_offset], read_bytes);
            bytes += read_bytes;
            pkt_offset += read_bytes;
        }
    }

     // 还有数据未被处理,设置 IP_MSG_TRUNC标志(Is set if the packet was truncated)

    if (pkt->end > pkt_offset)
        IP_BIT_SET(msg->msg_flags, IP_MSG_TRUNC);

    if (IP_BIT_ISFALSE(flags, IP_MSG_PEEK))
        /* Release packet. */

         // 释放协议栈空间的buffer
        ipcom_pkt_free(pkt, IP_FLAG_FC_STACKCONTEXT);

    return bytes;
}

从上面的代码逻辑来看,协议栈

1)用户态的程序通过socket收包时,是一个个packet为单位处理的。

2)如果用户态的缓存区大于报文大小,拷贝有效的数据后,不会再收下一个报文。

3)如果用户态的缓存区小于报文大小,截断拷贝,设置TUNC标志。

4)如果没有设置IP_MSG_PEEK(Leave the data on the receive buffer )标志,释放该报文的缓存。

 

2) 怎么处理呢?

    应用层协议,软件来负责处理

       参考协议定义,客户端/服务端交互各个阶段的消息大小有各自定义,收包的buffer大于或者等于消息大小。

                               TLV(type+length+value),length表示的就是后面消息的长度。

       协议提供协商,如sftp的OACK来协商数据块大小。

你可能感兴趣的:(C/C++,Networking)