一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何讓自己創(chuàng)建的tcp協(xié)議棧為其他應(yīng)用程序提供網(wǎng)絡(luò)服務(wù)?

FPGA之家 ? 來源:embed linux share ? 作者:embed linux share ? 2021-03-22 11:07 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

一般來說,使用套接字進(jìn)行網(wǎng)絡(luò)編程時(shí),默認(rèn)使用linux內(nèi)核提供的網(wǎng)絡(luò)服務(wù)。但是,現(xiàn)在我們自己在用戶空間構(gòu)建了一個tcp協(xié)議棧,并且讓它為其他應(yīng)用程序提供網(wǎng)絡(luò)服務(wù),這勢必要求我們自己實(shí)現(xiàn)一套新的套接字接口,并且提供給其他應(yīng)用程序指定使用。

但是,我們并不希望把該tcp協(xié)議棧封裝成動態(tài)庫的形式,因?yàn)檫@樣一來,應(yīng)用程序的編譯是必須要把庫一起連接進(jìn)去的。那么原生網(wǎng)絡(luò)編程開發(fā)的程序就不能基于我們tcp協(xié)議棧來運(yùn)行了。

一種較好的設(shè)計(jì)思路是,把tcp協(xié)議棧剝離出來作為一個獨(dú)立的組件來運(yùn)行,然后通過一個中間件,把網(wǎng)絡(luò)程序與tcp協(xié)議棧協(xié)同工作起來。這個中間件的主要工作就是負(fù)責(zé)偷龍換鳳,也就是把網(wǎng)絡(luò)程序中的內(nèi)核網(wǎng)絡(luò)服務(wù)轉(zhuǎn)換成獨(dú)立運(yùn)行的tcp協(xié)議棧的網(wǎng)絡(luò)服務(wù)。

核心思路:網(wǎng)絡(luò)程序(curl)+自定義套接字庫(liblevel.so)+tcp協(xié)議棧(level-ip),如下圖:

curl小工具

curl是一種命令行工具,作用是發(fā)出網(wǎng)絡(luò)請求,然后得到和提取數(shù)據(jù),顯示在"標(biāo)準(zhǔn)輸出"(stdout)上面。我們直接在curl命令后加上網(wǎng)址和端口,就可以看到網(wǎng)頁源碼。比如抓取www.sina.com網(wǎng)址:

curl www.sina.com 80

下面我們來看一個curl工具的簡易實(shí)現(xiàn),如下圖:

第3行:判斷目標(biāo)主機(jī)名是否合法

第11行:判斷目標(biāo)端口好是否合法

第16行:完成主機(jī)名到地址解析

第21行:使用socket申請一個套接字描述符

第23行:使用connect函數(shù)發(fā)起tcp連接

第30行:按照http 1.1協(xié)議來填充要發(fā)送的內(nèi)容,此處為http協(xié)議的get請求

第33行:調(diào)用write來發(fā)送網(wǎng)絡(luò)數(shù)據(jù)

第41行:在while循環(huán)中重復(fù)接收服務(wù)器返回來的網(wǎng)頁數(shù)據(jù),并且打印在當(dāng)前控制臺終端上。

這是標(biāo)準(zhǔn)的網(wǎng)絡(luò)應(yīng)用程序,使用gcc命令編譯后即可運(yùn)行。

gcc curl.c -o curl

liblevelip.so庫

level-ip腳本

liblevelip.so庫重新封裝了常用的socket套接字,并借助socket原生的本地套接字接口來與tcp協(xié)議棧(level-ip)進(jìn)行數(shù)據(jù)通信。以后在curl程序使用socket套接字時(shí),優(yōu)先使用該庫的服務(wù)接口,而不是內(nèi)核的網(wǎng)絡(luò)服務(wù)。這是通過level-ip這個shell腳本完成的,具體命令如下:

./level-ip curl www.sina.com 80

我們來分析一下level-ip這個shell腳本的原理,如下圖:

第1行:執(zhí)行該shell腳本由/bin/sh程序來執(zhí)行。

第3行:指定腳本如果發(fā)生錯誤,或者遇到不存在的變量就報(bào)錯,并停止執(zhí)行。

第5行:保存腳本的第一個參數(shù)到prog變量中。

第6行:去掉一個參數(shù),即原來的1,2,依此類推。

第8行:LD_PRELOAD是一個環(huán)境變量,其指定的動態(tài)庫加載等級最高。@表示第二個參數(shù)之后的全部參數(shù)。

綜上所述,我們就可以確定curl程序是優(yōu)先加載liblevelip.so庫來使用了,通過這種打樁技術(shù),我們可以在加載階段替換部分系統(tǒng)函數(shù)的調(diào)用,比如我們常用的socket接口。

liblevelip.c文件

liblevelip.so庫由liblevellip.c文件編譯而來,該文件在tools文件夾中,我們逐步來分析一下這個c文件。

__libc_start_main函數(shù)

首先是__libc_start_main函數(shù),該函數(shù)原本是glibc庫里面的函數(shù),curl程序里面的main函數(shù)就是從這里開始被調(diào)用。但是我們在liblevelip.c里面實(shí)現(xiàn)了這個函數(shù),并且liblevelip.so的庫加載順序優(yōu)先于glibc的動態(tài)庫加載。因此在執(zhí)行curl程序中的main函數(shù)之前,此函數(shù)先被執(zhí)行。如下圖:

第3行:dlsym函數(shù)里的第一個參數(shù)為RTLD_NEXT,這意味著我們將從其他動態(tài)庫去加載__libc_start_main函數(shù)符號(比如glibc庫),然后把函數(shù)句柄賦值給__start_main變量。

第7~22行:從glibc庫中加載一部分linux系統(tǒng)原生提供的系統(tǒng)調(diào)用接口。因?yàn)槲覀兊木W(wǎng)絡(luò)服務(wù)還是要依賴于一些更底層的系統(tǒng)調(diào)用接口的。

第24行:初始化一個鏈表節(jié)點(diǎn)lvlip_socks。

第26行:調(diào)用glibc的原生__libc_start_main接口。

socket函數(shù)

接下來就是liblevelip.so對外提供的第一個網(wǎng)絡(luò)編程接口--socket函數(shù)了。該函數(shù)實(shí)現(xiàn)如下:

第3~5行:檢查網(wǎng)絡(luò)通信協(xié)議族是否為tcp協(xié)議,如果不是tcp協(xié)議,則調(diào)用內(nèi)核提供的網(wǎng)絡(luò)服務(wù)。

第9行:借助tcp本地套接字接口,與tcp協(xié)議棧建立連接,用于通信的本地文件為/tmp/lvlip.socket

第11行:申請一個lvlip_sock類型的buff用于管理socket信息。結(jié)構(gòu)體類型如下:

struct lvlip_sock { struct list_head list; int lvlfd; /* For Level-IP IPC */ int fd;};

list成員變量為鏈表結(jié)點(diǎn)

lvlfd記錄與tcp協(xié)議棧通信的網(wǎng)絡(luò)文件描述符

fd記錄tcp協(xié)議棧的返回狀態(tài)發(fā)送socket消息給tcp協(xié)議棧第12行:記錄與tcp協(xié)議棧通信的網(wǎng)絡(luò)文件描述符到sock->lvlfd第13行:把這次的網(wǎng)絡(luò)通信消息加入lvlip_socks鏈表中第14行:網(wǎng)絡(luò)通信消息數(shù)量加1第16行:獲取當(dāng)前線程的pid號

第17~18行:申請ipc_msg+ipc_socket結(jié)構(gòu)體長度的buff,用于發(fā)送詳細(xì)的socket信息到tcp協(xié)議棧。結(jié)構(gòu)體定義如下:

struct ipc_msg { uint16_t type; pid_t pid; uint8_t data[];} __attribute__((packed));

type:記錄此次socket信息的具體類型

pid:記錄請求網(wǎng)絡(luò)服務(wù)的進(jìn)程pid號

data:存放具體的通信內(nèi)容

struct ipc_socket { int domain; int type; int protocol;} __attribute__((packed));

實(shí)際上就是soket函數(shù)的三個參數(shù)。

第23~29行:把ipc_socket作為通信的具體內(nèi)容填充到ipc_msg的data區(qū)域中去

第31行:調(diào)用transmit_lvlip()函數(shù)真正給tcp協(xié)議棧發(fā)送消息,并且等待協(xié)議棧的數(shù)據(jù)回復(fù)。

此處我們就把liblevelip.so中的socket函數(shù)給剖析清楚了,其他諸如close、connect、write、read、send、sendto、recv、此處我們就把liblevelip.so中的socket函數(shù)給剖析清楚了,其他諸如close、connect、write、read、send、sendto、recv、此處我們就把liblevelip.so中的socket函數(shù)給剖析清楚了,其他諸如close、connect、write、read、send、sendto、recv、recvfrom、poll、select等函數(shù),原理都是一樣的,此處不再展開分析。

tcp協(xié)議棧(level-ip)

用戶空間的level-ip協(xié)議棧,在運(yùn)行之初,就已經(jīng)在main函數(shù)里面創(chuàng)建了一系列線程。如下圖:

其中第9行,在run_threads()函數(shù)里創(chuàng)建了一系列線程,如下圖:

在這里,我們重點(diǎn)關(guān)注第5行創(chuàng)建的start_ipc_listener線程

該線程的實(shí)現(xiàn)如下:

第5行:指定tcp本地通信的路徑文件為"/tmp/lvlip.socket",與我們前面liblevelip.so庫的本地通信文件一致,這就說明它們之間確實(shí)是通過tco本地通信接口來通信的

第10行:調(diào)用socket接口開始進(jìn)行tcp本地通信

第24行:調(diào)用bind函數(shù)綁定本地通信路徑

第31行:調(diào)用listen函數(shù)監(jiān)聽指定端口,等待liblevelip.so庫發(fā)起連接

第46行:如果liblevelip.so庫發(fā)起連接,則調(diào)用accept函數(shù)準(zhǔn)備開始收發(fā)信息。

第54行:每監(jiān)聽到一個新的連接,新創(chuàng)建一個socket_ipc_open函數(shù)來進(jìn)行數(shù)據(jù)的具體收發(fā)。

socket_ipc_open函數(shù)主要是負(fù)責(zé)通信信息的讀取,然后根據(jù)通信消息的類型不同,來進(jìn)一步調(diào)用具體的處理函數(shù),其實(shí)現(xiàn)如下:

第7行:調(diào)用read函數(shù)進(jìn)行數(shù)據(jù)的讀取

第8行:調(diào)用具體指令的回調(diào)信息

demux_ipc_socket_call的函數(shù)非常簡單,實(shí)現(xiàn)如下:

前面我們在liblevelip.so庫中調(diào)用socket()函數(shù)的時(shí)候,發(fā)送的消息類型為IPC_SOCKET,所以在此處我們進(jìn)一步分析ipc_socket()這個函數(shù)。

它的具體實(shí)現(xiàn)如下:

我們重點(diǎn)是關(guān)注第7行的_socket函數(shù),該函數(shù)就是tcp協(xié)議棧的核心接口之一了,它是整個tcp協(xié)議棧的真正入口,我們以后再來專門分析這個接口。然后第9行,ipc_write函數(shù)負(fù)責(zé)把tcp協(xié)議棧的處理結(jié)果返回給liblevelip.so庫,代碼較為簡單,此處不再分析。

原文標(biāo)題:Linux系統(tǒng)中間件的巧妙實(shí)現(xiàn)--以用戶空間的tcp協(xié)議棧為例

文章出處:【微信公眾號:FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11509

    瀏覽量

    213724

原文標(biāo)題:Linux系統(tǒng)中間件的巧妙實(shí)現(xiàn)--以用戶空間的tcp協(xié)議棧為例

文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    51+單片機(jī)TCP-IP+協(xié)議ZLIP源碼

    概述 單片機(jī)上網(wǎng)技術(shù),是當(dāng)前的一個熱門技術(shù)。單片機(jī)上網(wǎng)技術(shù)中的一個重要部分是在單片上實(shí)現(xiàn) TCP/IP 協(xié)議?,F(xiàn)在可獲得的 TCP/IP 源代碼一般并不為 51 單片機(jī)設(shè)計(jì),而 51
    發(fā)表于 04-22 15:11

    《DNESP32S3使用指南-IDF版_V1.6》第四十七章 lwIP初探

    是一個分層結(jié)構(gòu)的模型,每一層負(fù)責(zé)不同的網(wǎng)絡(luò)功能。整個協(xié)議可以被分為四層,從上到下分別是:應(yīng)用層、傳輸層、網(wǎng)絡(luò)層和網(wǎng)絡(luò)接口層。1,應(yīng)用層:這
    發(fā)表于 02-07 09:28

    百問FB網(wǎng)絡(luò)編程 - 網(wǎng)絡(luò)編程簡介

    協(xié)議網(wǎng)絡(luò)硬件和軟件。 分層提供了一種結(jié)構(gòu)化方式來討論系統(tǒng)組件。模塊化使更新系統(tǒng)組件更為容易。 協(xié)議是各層所有
    發(fā)表于 12-04 09:46

    socket 和 UDP 協(xié)議的對比

    。 Socket 定義 Socket 是一個抽象層,它提供了一種方式,使得應(yīng)用程序能夠發(fā)送和接收數(shù)據(jù)。在網(wǎng)絡(luò)編程中,Socket 允許程序創(chuàng)建
    的頭像 發(fā)表于 11-12 14:28 ?895次閱讀

    飛凌嵌入式ElfBoard ELF 1板卡-網(wǎng)絡(luò)編程示例之網(wǎng)絡(luò)基礎(chǔ)知識

    (1)UDP 不提供復(fù)雜的控制機(jī)制,利用 IP 提供面向無連接的通信服務(wù)。(2)并且它是將應(yīng)用程序發(fā)來的數(shù)據(jù)在收到的那一刻,立即按照原樣發(fā)送到網(wǎng)絡(luò)
    發(fā)表于 11-09 14:37

    什么是socket編程 socket與tcp/ip協(xié)議的關(guān)系

    基于TCP/IP協(xié)議族,這是一組用于網(wǎng)絡(luò)通信的協(xié)議,包括傳輸控制協(xié)議TCP)和互聯(lián)網(wǎng)
    的頭像 發(fā)表于 11-01 16:01 ?1196次閱讀

    TCP協(xié)議是什么

    ,應(yīng)用層之下,各種應(yīng)用提供可靠的、面向連接的、基于字節(jié)流的傳輸服務(wù)。本文將詳細(xì)解析TCP協(xié)議的定義、工作原理、主要特點(diǎn)及其在各種應(yīng)用場景中
    的頭像 發(fā)表于 10-09 13:54 ?1784次閱讀

    飛凌嵌入式ElfBoard ELF 1板卡-常見網(wǎng)絡(luò)服務(wù)搭建之SSH服務(wù)搭建

    SSHSecure Shell的縮寫,由IETF的網(wǎng)絡(luò)小組(Network Working Group)所制定的建立在應(yīng)用層基礎(chǔ)上的安全協(xié)議。SSH是較可靠,專為遠(yuǎn)程登錄會話和其他
    發(fā)表于 09-29 09:48

    飛凌嵌入式ElfBoard ELF 1板卡-常見網(wǎng)絡(luò)服務(wù)搭建之SSH服務(wù)搭建

    SSHSecure Shell的縮寫,由IETF的網(wǎng)絡(luò)小組(Network Working Group)所制定的建立在應(yīng)用層基礎(chǔ)上的安全協(xié)議。SSH是較可靠,專為遠(yuǎn)程登錄會話和其他
    發(fā)表于 09-27 09:06

    飛凌嵌入式ElfBoard ELF 1板卡-常見網(wǎng)絡(luò)服務(wù)搭建之TFTP服務(wù)搭建

    TFTP(Trivial File Transfer Protocol,簡單文件傳輸協(xié)議),是TCP/IP協(xié)議族中用來在客戶機(jī)和服務(wù)器之間進(jìn)行簡單文件傳輸?shù)?/div>
    發(fā)表于 09-25 09:44

    Linux網(wǎng)絡(luò)協(xié)議的實(shí)現(xiàn)

    網(wǎng)絡(luò)協(xié)議是操作系統(tǒng)核心的一個重要組成部分,負(fù)責(zé)管理網(wǎng)絡(luò)通信中的數(shù)據(jù)包處理。在 Linux 操作系統(tǒng)中,網(wǎng)絡(luò)
    的頭像 發(fā)表于 09-10 09:51 ?689次閱讀
    Linux<b class='flag-5'>網(wǎng)絡(luò)</b><b class='flag-5'>協(xié)議</b><b class='flag-5'>棧</b>的實(shí)現(xiàn)

    串口服務(wù)器和TCP/IP協(xié)議是什么關(guān)系

    串口服務(wù)器與TCP/IP協(xié)議之間存在著緊密而復(fù)雜的關(guān)系。這種關(guān)系主要體現(xiàn)在串口服務(wù)器如何利用TCP
    的頭像 發(fā)表于 08-25 17:35 ?2121次閱讀

    嵌入式學(xué)習(xí)-常見的shell命令之網(wǎng)絡(luò)相關(guān)命令

    ,提供了很好的參考模型。在OSI七層結(jié)構(gòu)中,每一層規(guī)定了不同的特性,負(fù)責(zé)不同的功能:應(yīng)用層(Application Layer):用戶接口,應(yīng)用程序提供訪問
    發(fā)表于 08-21 09:41

    常見的shell命令之網(wǎng)絡(luò)相關(guān)命令

    ,提供了很好的參考模型。在OSI七層結(jié)構(gòu)中,每一層規(guī)定了不同的特性,負(fù)責(zé)不同的功能:應(yīng)用層(Application Layer):用戶接口,應(yīng)用程序提供訪問
    發(fā)表于 08-20 09:50

    一文了解TCP/IP協(xié)議

    TCP/IP協(xié)議是現(xiàn)代計(jì)算機(jī)網(wǎng)絡(luò)通信的基礎(chǔ),是互聯(lián)網(wǎng)及局域網(wǎng)廣泛使用的一套協(xié)議TCP/IP協(xié)議
    的頭像 發(fā)表于 08-07 15:38 ?3508次閱讀
    一文了解<b class='flag-5'>TCP</b>/IP<b class='flag-5'>協(xié)議</b>