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來協商數據塊大小。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章