用戶態(tài)協(xié)議棧的實現(xiàn)

協(xié)議棧,指的是TCP/IP協(xié)議棧。linux系統(tǒng)中,協(xié)議棧是內(nèi)核實現(xiàn)的。

Client發(fā)送數(shù)據(jù)給server,數(shù)據(jù)首先到達網(wǎng)卡,經(jīng)過兩步到達應用程序
1)將數(shù)據(jù)從網(wǎng)卡的內(nèi)存copy到內(nèi)核協(xié)議棧,內(nèi)核協(xié)議棧對數(shù)據(jù)包進行解析;
2)應用程序通過調(diào)用recv函數(shù),將數(shù)據(jù)從內(nèi)核copy進用戶空間,得到應用層的數(shù)據(jù)包。
網(wǎng)卡的作用,接收的時候,是將光電信號轉(zhuǎn)換成數(shù)字信號;發(fā)送的時候,將數(shù)字信號轉(zhuǎn)換成光電信號。

什么是用戶態(tài)協(xié)議棧呢?就是將協(xié)議棧,做到應用程序。為什么要這么做呢?減少了一次數(shù)據(jù)copy的過程,繞過內(nèi)核,數(shù)據(jù)可以直接從網(wǎng)卡copy到應用程序,對于性能會有很大的提升。


image.png

為什么要有用戶態(tài)協(xié)議棧呢?是為了解決C10M的問題。

之前說過C10K的問題,使用epoll可以解決C10K的問題?,F(xiàn)在epoll已經(jīng)可以支持兩三百萬的并發(fā)了。
什么是C10M問題?
實現(xiàn)10M(即1千萬)的并發(fā)連接挑戰(zhàn)意味著什么:(網(wǎng)上找的)
1)1千萬的并發(fā)連接數(shù);
2)100萬個連接/秒:每個連接以這個速率持續(xù)約10秒;
3)10GB/秒的連接:快速連接到互聯(lián)網(wǎng);
4)1千萬個數(shù)據(jù)包/秒:據(jù)估計目前的服務器每秒處理50K數(shù)據(jù)包,以后會更多;
5)10微秒的延遲:可擴展服務器也許可以處理這個規(guī)模(但延遲可能會飆升);
6)10微秒的抖動:限制最大延遲;
7)并發(fā)10核技術:軟件應支持更多核的服務器(通常情況下,軟件能輕松擴展到四核,服務器可以擴展到更多核,因此需要重寫軟件,以支持更多核的服務器).

我們來計算一下,單機承載1000萬連接,需要的硬件資源:
內(nèi)存:1個連接,大概需要4k recvbuffer,4k sendbuffer,一共需要10M * 8k = 80G
CPU:10M 除以 50K = 200核
只是支持這么多連接,還沒有做其他事情,就需要這么多的資源,如果在加上其他的限制,加上業(yè)務的處理,資源肯定會更多。使用用戶態(tài)協(xié)議棧,可以減少一次數(shù)據(jù)的copy,可以節(jié)省很大一部分資源。

要實現(xiàn)用戶態(tài)協(xié)議棧,很關鍵的一個問題,是網(wǎng)絡數(shù)據(jù)怎么才能繞過內(nèi)核,直接到達用戶空間?netmap、dpdk為用戶態(tài)協(xié)議棧的實現(xiàn),提供了可能。

這次我們使用了netmap實現(xiàn)用戶態(tài)協(xié)議棧,后面會介紹dpdk。

netmap主要利用了mmap,將網(wǎng)卡中數(shù)據(jù),直接映射到內(nèi)存。netmap直接接管網(wǎng)卡數(shù)據(jù),可以繞過內(nèi)核協(xié)議棧。我們直接在應用程序中實現(xiàn)協(xié)議棧,對協(xié)議進行解析,就可以獲取到網(wǎng)絡數(shù)據(jù)了。


image.png

netmap可以在github上下載,按照上面的readme編譯安裝,使用比較方便。
https://github.com/luigirizzo/netmap

使用netmap實現(xiàn)了一個簡單的udp server, 運行的時候,注意要使用兩塊網(wǎng)卡,不然eth0的網(wǎng)卡被我們的程序接管了,ssh就無法登陸了。


#include <stdio.h>
#include <sys/poll.h>


#define NETMAP_WITH_LIBS

#include <net/netmap_user.h>


#pragma pack(1)

#define PROTO_IP        0x0800
#define PROTO_UDP       0x11


#define MAC_LEN         6

struct ethhdr {

    unsigned char h_dest[MAC_LEN]; //mac
    unsigned char h_src[MAC_LEN];
    unsigned short h_proto;

};
// sizeof(struct ethhdr) == 14

struct iphdr {

    unsigned char version:4,
                  hdrlen:4;

    unsigned char tos; //
    unsigned short length;

    unsigned short id;

    unsigned short flag:3,
                   offset:13;

    unsigned char ttl;
    unsigned char proto;

    unsigned short check;

    unsigned int sip;
    unsigned int dip;

};

// sizeof(struct ip) == 20

struct udphdr {

    unsigned short sport;
    unsigned short dport;
    unsigned short length;
    unsigned short check;

};

// sizeof(udphdr)  8


struct udppkt {

    struct ethhdr eh; // 14
    struct iphdr ip;  // 20
    struct udphdr udp; // 8

    unsigned char body[0]; // sizeof(body)=0;
    

};

// sizeof(udppkt) = 44


// netmap:eth0
// eth0
int main() {

    // eth0  --> ens33
    struct nm_desc *nmr = nm_open("netmap:eth0", NULL, 0, NULL);
    if (nmr == NULL) {
        return -1;
    }

    struct pollfd pfd = {0};
    pfd.fd = nmr->fd; //
    pfd.events = POLLIN;
// select/poll  or epoll
// poll --> select
    while (1) {

        int ret = poll(&pfd, 1, -1);
        if (ret < 0) continue;

        if (pfd.revents & POLLIN) {
            struct nm_pkthdr h;
            unsigned char *stream = nm_nextpkt(nmr, &h); // read

            struct ethhdr *eh = (struct ethhdr*)stream;

            // 0x0800
            if (ntohs(eh->h_proto) == PROTO_IP) {

                struct udppkt *udp = (struct udppkt *)stream;

                if (udp->ip.proto == PROTO_UDP) {

                    //
                    int udp_length = ntohs(udp->udp.length);

                    udp->body[udp_length-8] = '\0';

                    printf("udp --> %s\n", udp->body);
                    
                }

            }

        }

    }

    return 0;
}

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容