chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

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

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

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

基于Select/Poll實(shí)現(xiàn)并發(fā)服務(wù)器(一)

嵌入式大雜燴 ? 來(lái)源:嵌入式大雜燴 ? 作者:嵌入式大雜燴 ? 2022-06-20 00:20 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

開發(fā)環(huán)境:

RT-Thread版本:4.0.3

操作系統(tǒng):Windows10

Keil版本:V5.30

RT-Thread Studio版本:2.0.1

開發(fā)板MCUSTM32H750XB

LWIP:2.0.2

并發(fā)服務(wù)器支持多個(gè)客戶端的同時(shí)連接,最大可接入的客戶端數(shù)取決于內(nèi)核控制塊的個(gè)數(shù)。當(dāng)使用Socket API時(shí),要使服務(wù)器能夠同時(shí)支持多個(gè)客戶端的連接,必須引入多任務(wù)機(jī)制,為每個(gè)連接創(chuàng)建一個(gè)單獨(dú)的任務(wù)來(lái)處理連接上的數(shù)據(jù),多任務(wù)可以是多線程或者多進(jìn)程,這是最常用的并發(fā)服務(wù)器設(shè)計(jì)。但是多線程/多進(jìn)程消耗資源多,處理起來(lái)也比較復(fù)雜,本文將基于LWIP協(xié)議棧的Select/Poll機(jī)制實(shí)現(xiàn)并發(fā)服務(wù)器。

1 IO模型概述

在具體講解基于Select/Poll機(jī)制實(shí)現(xiàn)并發(fā)服務(wù)器之前,我們需要了解IO的相關(guān)概念,所謂IO就是,就是數(shù)據(jù)的讀寫,一般分為網(wǎng)絡(luò)IO(本質(zhì)就是socket讀寫)和磁盤IO。

IO模型大致可以分為:同步阻塞、同步非阻塞、異步、信號(hào)驅(qū)動(dòng)。

poYBAGKvMWeAWCgZAAEohJIEplU624.png

可細(xì)分為5種I/O模型:

1)阻塞I/O,進(jìn)程處于阻塞模式時(shí),讓出CPU,進(jìn)入休眠狀態(tài);

2)非阻塞I/O,非阻塞模式的使用并不普遍,因?yàn)榉亲枞J綍?huì)浪費(fèi)大量的CPU資源;

3)I/O復(fù)用(select和poll),針對(duì)批量IP操作時(shí),使用I/O多路復(fù)用,非常有好;

4)異步I/O(POSIX的aio_系列函數(shù))

5)信號(hào)驅(qū)動(dòng)I/O(SIGIO)

一個(gè)輸入操作通常包括兩個(gè)不同的階段:

1)等待數(shù)據(jù)準(zhǔn)備好;

2)從內(nèi)核向進(jìn)程復(fù)制數(shù)據(jù);

對(duì)于一個(gè)套接字的輸入操作,第一步通常涉及等待數(shù)據(jù)從網(wǎng)絡(luò)中到達(dá)。當(dāng)所等待分組到達(dá)時(shí),它被復(fù)制到內(nèi)核中某個(gè)緩沖區(qū)。第二步就是把數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到應(yīng)用進(jìn)程緩沖區(qū)。

1.1阻塞I/O

阻塞 I/O模式是最普遍使用的 I/O模式。一個(gè)套接字建立后所處于的模式就是阻塞 I/O模式。(因?yàn)?a href="http://www.brongaenegriffin.com/v/tag/538/" target="_blank">Linux系統(tǒng)默認(rèn)的IO模式是阻塞模式)。對(duì)于一個(gè) UDP套接字來(lái)說(shuō),數(shù)據(jù)就緒的標(biāo)志比較簡(jiǎn)單:

(1)已經(jīng)收到了一整個(gè)數(shù)據(jù)報(bào)

(2)沒(méi)有收到。

而 TCP這個(gè)概念就比較復(fù)雜,需要附加一些其他的變量。

最流行的I/O模型是阻塞式I/O(blocking I/O) 模型,默認(rèn)情況下,所有的套接字都是阻塞的。阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起(線程進(jìn)入非可執(zhí)行狀態(tài),在這個(gè)狀態(tài)下,CPU不會(huì)給線程分配時(shí)間片,即線程暫停運(yùn)行)。函數(shù)只有在得到結(jié)果之后才會(huì)返回。以數(shù)據(jù)包套接字為例,如圖。

poYBAGKvMZOAOGqKAAEVSw_i33g481.png

進(jìn)程調(diào)用recvfrom,其系統(tǒng)調(diào)用直到數(shù)據(jù)報(bào)到達(dá)且被拷貝到應(yīng)用進(jìn)程的緩沖區(qū)或者發(fā)生錯(cuò)誤才返回。最常見的錯(cuò)誤是系統(tǒng)調(diào)用被信號(hào)中斷。我們說(shuō)進(jìn)程從調(diào)用recvfrom開始到它返回的整段時(shí)間內(nèi)是被阻塞的,recvfrom成功返回后,進(jìn)程開始處理數(shù)據(jù)報(bào)。

1.2非阻塞I/O

進(jìn)程把一個(gè)套接口設(shè)置成非阻塞是在通知內(nèi)核:當(dāng)所請(qǐng)求的I/O操作非得把本進(jìn)程投入睡眠才能完成時(shí),不要把本進(jìn)程投入睡眠,而是返回一個(gè)錯(cuò)誤。

poYBAGKvMbCAFZKRAAFvRl2AOgY598.png

前三次調(diào)用recvfrom時(shí)沒(méi)有數(shù)據(jù)可返回,因此內(nèi)核轉(zhuǎn)而立即返回一個(gè)EWOULDBLOCK錯(cuò)誤。第四次調(diào)用 recvfrom時(shí)已有一個(gè)數(shù)據(jù)報(bào)準(zhǔn)備好,它被復(fù)制到應(yīng)用程序緩沖區(qū),于是recvfrom成功返回。我們接著處理數(shù)據(jù)。

當(dāng)一個(gè)應(yīng)用程序使用了非阻塞模式的套接字,它需要使用一個(gè)循環(huán)來(lái)不聽的測(cè)試是否一個(gè)文件描述符有數(shù)據(jù)可讀(稱做 polling(輪詢))。應(yīng)用程序不停的 polling內(nèi)核來(lái)檢查是否 I/O操作已經(jīng)就緒。這將是一個(gè)極浪費(fèi) CPU資源的操作。這種模式使用中不是很普遍。

非阻塞和阻塞的概念相對(duì)應(yīng),指在不能立刻得到結(jié)果之前,該函數(shù)不會(huì)阻塞當(dāng)前線程,而會(huì)立刻返回。

1.3 I/O復(fù)用

在使用 I/O多路技術(shù)的時(shí)候,我們調(diào)用 select()函數(shù)和 poll()函數(shù),在調(diào)用它們的時(shí)候阻塞,而不是我們來(lái)調(diào)用 recvfrom(或recv)的時(shí)候阻塞。主要可以調(diào)用select和poll;對(duì)一個(gè)IO端口,兩次調(diào)用,兩次返回,比阻塞IO并沒(méi)有什么優(yōu)越性;關(guān)鍵是能實(shí)現(xiàn)同時(shí)對(duì)多個(gè)IO端口進(jìn)行監(jiān)聽,可以等待多個(gè)描述符就緒。

I/O復(fù)用模型會(huì)用到select、poll,這幾個(gè)函數(shù)也會(huì)使進(jìn)程阻塞,但是和阻塞I/O所不同的的,這兩個(gè)函數(shù)可以同時(shí)阻塞多個(gè)I/O操作。而且可以同時(shí)對(duì)多個(gè)讀操作,多個(gè)寫操作的I/O函數(shù)進(jìn)行檢測(cè),直到有數(shù)據(jù)可讀或可寫時(shí),才真正調(diào)用I/O操作函數(shù)。

當(dāng)我們調(diào)用 select函數(shù)阻塞的時(shí)候,select函數(shù)等待數(shù)據(jù)報(bào)套接字進(jìn)入讀就緒狀態(tài)。當(dāng)select函數(shù)返回的時(shí)候,也就是套接字可以讀取數(shù)據(jù)的時(shí)候。這時(shí)候我們就可以調(diào)用 recvfrom函數(shù)來(lái)將數(shù)據(jù)拷貝到我們的程序緩沖區(qū)中。

對(duì)于單個(gè)I/O操作,和阻塞模式相比較,select()和poll()并沒(méi)有什么高級(jí)的地方。而且,在阻塞模式下只需要調(diào)用一個(gè)函數(shù):讀取或發(fā)送函數(shù)。在使用了多路復(fù)用技術(shù)后,我們需要調(diào)用兩個(gè)函數(shù)了:先調(diào)用 select()函數(shù)或poll()函數(shù),然后才能進(jìn)行真正的讀寫。

多路復(fù)用的高級(jí)之處在于:它能同時(shí)等待多個(gè)文件描述符,而這些文件描述符(套接字描述符)其中的任意一個(gè)進(jìn)入讀就緒狀態(tài),select()函數(shù)就可以返回。

pYYBAGKvMdeAYlOlAAFzoeeT2H0033.png

IO多路技術(shù)一般在下面這些情況中被使用:

  • 當(dāng)一個(gè)客戶端需要同時(shí)處理多個(gè)文件描述符的輸入輸出操作的時(shí)候(一般來(lái)說(shuō)是標(biāo)準(zhǔn)的輸入輸出和網(wǎng)絡(luò)套接字),I/O多路復(fù)用技術(shù)將會(huì)有機(jī)會(huì)得到使用。
  • 當(dāng)程序需要同時(shí)進(jìn)行多個(gè)套接字的操作的時(shí)候。
  • 如果一個(gè) TCP服務(wù)器程序同時(shí)處理正在偵聽網(wǎng)絡(luò)連接的套接字和已經(jīng)連接好的套接字。
  • 如果一個(gè)服務(wù)器程序同時(shí)使用 TCP和 UDP協(xié)議。
  • 如果一個(gè)服務(wù)器同時(shí)使用多種服務(wù)并且每種服務(wù)可能使用不同的協(xié)議(比如 inetd就是這樣的)。

1.4異步I/O模型

異步I/O(asynchronous I/O)有POSIX規(guī)范定義。后來(lái)演變成當(dāng)前POSIX規(guī)范的各種早期標(biāo)準(zhǔn)定義的實(shí)時(shí)函數(shù)中存在的差異已經(jīng)取得一致。一般地說(shuō),這些函數(shù)的工作機(jī)制是:告知內(nèi)核啟動(dòng)某個(gè)操作,并讓內(nèi)核在整個(gè)操作(包括將數(shù)據(jù)從內(nèi)核拷貝到我們自己的緩沖區(qū))完成后通知我們。這種模型與前與前面介紹的信號(hào)驅(qū)動(dòng)模型的主要區(qū)別在于:信號(hào)驅(qū)動(dòng)I/O是由內(nèi)核通知我們何時(shí)可以啟動(dòng)一個(gè)I/O操作,而異步I/O模型是由內(nèi)核通知我們I/O操作何時(shí)完成。

poYBAGKvMfOAV7qOAAE5v-Hf4zM819.png

1.5信號(hào)驅(qū)動(dòng)I/O模型

我們也可以用信號(hào),讓內(nèi)核在描述字就緒時(shí)發(fā)送SIGIO信號(hào)通知我們。我們稱這種模型為信號(hào)驅(qū)動(dòng)I/O(signal-driven I/O)。

我們首先開啟套接口的信號(hào)驅(qū)動(dòng)I/O功能,并通過(guò)sigaction系統(tǒng)調(diào)用安裝一個(gè)信號(hào)處理函數(shù)。該系統(tǒng)調(diào)用立即發(fā)回,我們的進(jìn)程繼續(xù)工作,也就是說(shuō)它沒(méi)有被阻塞。當(dāng)數(shù)據(jù)報(bào)準(zhǔn)備好時(shí),內(nèi)核就為該進(jìn)程產(chǎn)生一個(gè)SIGIO信號(hào)。我們隨后既可以在信號(hào)處理函數(shù)中調(diào)用recvfrom讀取數(shù)據(jù)報(bào),并通知主循環(huán)數(shù)據(jù)已經(jīng)準(zhǔn)備好待處理,也可以立即通知主循環(huán),讓它讀取數(shù)據(jù)報(bào)。

無(wú)論如何處理SIGIO信號(hào),這種模型的優(yōu)勢(shì)在于等待數(shù)據(jù)報(bào)到達(dá)期間,進(jìn)程不被阻塞。主循環(huán)可以繼續(xù)執(zhí)行,只要不時(shí)等待來(lái)自信號(hào)處理函數(shù)的通知:既可以是數(shù)據(jù)已經(jīng)準(zhǔn)備好被處理,也可以是數(shù)據(jù)報(bào)已準(zhǔn)備好被讀取。

poYBAGKvMgyAO8zdAAGHYr595FM613.png

1.6各種模型的比較

各種模型的比較如下圖所示,可以看出,前4種模型的主要區(qū)別在于第一階段,因?yàn)樗鼈兊牡诙A段是一樣的:在數(shù)據(jù)從內(nèi)核復(fù)制到調(diào)用者的緩沖區(qū)起見,進(jìn)程阻塞與recvfrom調(diào)用,相反。異步I/O模型在這兩個(gè)階段都需要處理,從而不同于其他四種模型。

poYBAGKvMiWATzBqAAG55wWa2bY569.png
  • 同步I/O與異步I/O對(duì)比

POSIX把這兩個(gè)術(shù)語(yǔ)定義如下:

·同步I/O操作(synchronous I/O operation)導(dǎo)致請(qǐng)求進(jìn)程阻塞,直到I/O操作完成。

·異步I/O(asynchronous I/O operation)不導(dǎo)致請(qǐng)求進(jìn)程阻塞。

根據(jù)上述定義,我們前4種模型----阻塞I/O模型、非阻塞I/O模型、I/O復(fù)用模型和信號(hào)去驅(qū)動(dòng)I/O模型都是同步I/O模型,因?yàn)槠渲姓嬲腎/O操作(recvfrom)將阻塞進(jìn)程。只有異步I/O模型與POSIX定義的異步I/O相匹配。

本文的要將的I/O復(fù)用,本質(zhì)就是select/poll機(jī)制。因此,其他IO有興趣可以去了解。

2 RT-thread的網(wǎng)絡(luò)架構(gòu)

RT-Thread的網(wǎng)絡(luò)框架結(jié)構(gòu)如下所示:

poYBAGKvMj-AVxm8AABpdb_PAWU941.png

最頂層是網(wǎng)絡(luò)應(yīng)用層,提供一套標(biāo)準(zhǔn) BSD Socket API,如 socket、connect等函數(shù),用于系統(tǒng)中大部分網(wǎng)絡(luò)開發(fā)應(yīng)用, BSD Socket API已經(jīng)是網(wǎng)絡(luò)套接字的事實(shí)上的抽象標(biāo)準(zhǔn)。使用BSD Socket API編寫應(yīng)用,不會(huì)依賴具體的操作系統(tǒng),但是底層的具體實(shí)現(xiàn)是依賴操作系統(tǒng)的。

第二部分為 SAL套接字抽象層,通過(guò)它 RT-Thread系統(tǒng)能夠適配下層不同的網(wǎng)絡(luò)協(xié)議棧,并提供給上層統(tǒng)一的網(wǎng)絡(luò)編程接口,方便不同協(xié)議棧的接入。套接字抽象層為上層應(yīng)用層提供接口有:accept、connect、send、recv等。

第三部分為 netdev網(wǎng)卡層,主要作用是解決多網(wǎng)卡情況設(shè)備網(wǎng)絡(luò)連接和網(wǎng)絡(luò)管理相關(guān)問(wèn)題,通過(guò) netdev網(wǎng)卡層用戶可以統(tǒng)一管理各個(gè)網(wǎng)卡信息和網(wǎng)絡(luò)連接狀態(tài),并且可以使用統(tǒng)一的網(wǎng)卡調(diào)試命令接口。

第四部分為協(xié)議棧層,該層包括幾種常用的 TCP/IP協(xié)議棧,例如嵌入式開發(fā)中常用的輕型 TCP/IP協(xié)議棧 lwIP以及 RT-Thread自主研發(fā)的 AT Socket網(wǎng)絡(luò)功能實(shí)現(xiàn)等。這些協(xié)議棧或網(wǎng)絡(luò)功能實(shí)現(xiàn)直接和硬件接觸,完成數(shù)據(jù)從網(wǎng)絡(luò)層到傳輸層的轉(zhuǎn)化。

最后一層為硬件層,ETH是唯一的有線網(wǎng)絡(luò)接入方式,其余都是無(wú)線網(wǎng)絡(luò)接入方式,LTE模組,Cat模組,NB-IOT模組這些依賴基站運(yùn)營(yíng)商的入網(wǎng)方式,例如 SIM800,EC25,AIR720,L610,N58,M5311等,這些不同廠家,不同工作頻率的模組均可以通過(guò) NET組件入網(wǎng);WIFI這種無(wú)需運(yùn)營(yíng)商直接提供的網(wǎng)絡(luò)的入網(wǎng)方式,例如 ESP8266,W60x,AP6212,rw007等。

RT-Thread的網(wǎng)絡(luò)應(yīng)用層提供的接口主要以標(biāo)準(zhǔn) BSD Socket API為主,這樣能確保程序可以在 Windows或者Linux上編寫、調(diào)試,然后再移植到 RT-Thread操作系統(tǒng)上。

RT-Thread對(duì)于不同的協(xié)議?;蚓W(wǎng)絡(luò)功能實(shí)現(xiàn),網(wǎng)絡(luò)接口的名稱可能各不相同,以 connect連接函數(shù)為例,lwIP協(xié)議棧中接口名稱為 lwip_connect,而 AT Socket網(wǎng)絡(luò)實(shí)現(xiàn)中接口名稱為 at_connect。SAL組件提供對(duì)不同協(xié)議?;蚓W(wǎng)絡(luò)實(shí)現(xiàn)接口的抽象和統(tǒng)一,組件在 socket創(chuàng)建時(shí)通過(guò)判斷傳入的協(xié)議簇(domain)類型來(lái)判斷使用的協(xié)議?;蚓W(wǎng)絡(luò)功能,完成 RT-Thread系統(tǒng)中多協(xié)議的接入與使用。

目前 SAL組件支持的協(xié)議?;蚓W(wǎng)絡(luò)實(shí)現(xiàn)類型有:lwIP協(xié)議棧、AT Socket協(xié)議棧、WIZnet硬件 TCP/IP協(xié)議棧

int socket(int domain, int type, int protocol);

上述為標(biāo)準(zhǔn) BSD Socket API中 socket創(chuàng)建函數(shù)的定義,domain表示協(xié)議域又稱為協(xié)議簇(family),用于判斷使用哪種協(xié)議?;蚓W(wǎng)絡(luò)實(shí)現(xiàn),AT Socket協(xié)議棧使用的簇類型為 AF_AT,lwIP協(xié)議棧使用協(xié)議簇類型有 AF_INET等,WIZnet協(xié)議棧使用的協(xié)議簇類型為 AF_WIZ。

對(duì)于不同的軟件包,socket傳入的協(xié)議簇類型可能是固定的,不會(huì)隨著 SAL組件接入方式的不同而改變。為了動(dòng)態(tài)適配不同協(xié)議棧或網(wǎng)絡(luò)實(shí)現(xiàn)的接入,SAL組件中對(duì)于每個(gè)協(xié)議棧或者網(wǎng)絡(luò)實(shí)現(xiàn)提供兩種協(xié)議簇類型匹配方式:主協(xié)議簇類型和次協(xié)議簇類型。socket創(chuàng)建時(shí)先判斷傳入?yún)f(xié)議簇類型是否存在已經(jīng)支持的主協(xié)議類型,如果是則使用對(duì)應(yīng)協(xié)議?;蚓W(wǎng)絡(luò)實(shí)現(xiàn),如果不是判斷次協(xié)議簇類型是否支持。目前系統(tǒng)支持協(xié)議簇類型如下:

  • lwIP協(xié)議棧: family = AF_INET、sec_family = AF_INET
  • AT Socket協(xié)議棧: family = AF_AT、sec_family = AF_INET
  • WIZnet硬件 TCP/IP協(xié)議棧: family = AF_WIZ、sec_family = AF_INET

SAL組件主要作用是統(tǒng)一抽象底層 BSD Socket API接口,下面以 bind函數(shù)調(diào)用流程為例說(shuō)明 SAL組件函數(shù)調(diào)用方式:

  • bind:SAL組件對(duì)外提供的抽象的 BSD Socket API,用于統(tǒng)一 fd管理;
  • sal_bind:SAL組件中 bind實(shí)現(xiàn)函數(shù),用于指定端口和網(wǎng)卡(當(dāng)存在多個(gè)網(wǎng)卡的時(shí)候)。
  • lwip_bind:底層協(xié)議棧提供的層 bind連接函數(shù),在網(wǎng)卡初始化完成時(shí)注冊(cè)到 SAL組件中,最終調(diào)用的操作函數(shù)。

/* SAL組件為應(yīng)用層提供的標(biāo)準(zhǔn) BSD Socket API */

int bind(int s, const struct sockaddr *name, socklen_t namelen)
{
    /*獲取 SAL套接字描述符 */
int socket = dfs_net_getsocket(s);

    /*通過(guò) SAL套接字描述符執(zhí)行 sal_bind函數(shù) */
    return sal_bind(socket, name, namelen);
}

/* SAL組件抽象函數(shù)接口實(shí)現(xiàn) */

int sal_bind(int socket, const struct sockaddr *name, socklen_t namelen)
{
    struct sal_socket *sock;
    struct sal_proto_family *pf;
    ip_addr_t input_ipaddr;

    RT_ASSERT(name);

    /* get the socket object by socket descriptor */
    SAL_SOCKET_OBJ_GET(sock, socket);

    /* bind network interface by ip address */
    sal_sockaddr_to_ipaddr(name, &input_ipaddr);

    /* check input ipaddr is default netdev ipaddr */
    if (!ip_addr_isany_val(input_ipaddr))
    {
        struct sal_proto_family *input_pf = RT_NULL, *local_pf = RT_NULL;
        struct netdev *new_netdev = RT_NULL;

        new_netdev = netdev_get_by_ipaddr(&input_ipaddr);
        if (new_netdev == RT_NULL)
        {
            return -1;
        }

        /* get input and local ip address proto_family */
       SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, local_pf, bind);
        SAL_NETDEV_SOCKETOPS_VALID(new_netdev, input_pf, bind);

        /* check the network interface protocol family type */
        if (input_pf->family != local_pf->family)
        {
            int new_socket = -1;

            /* protocol family is different, close old socket and create new socket by input ip address */
           local_pf->skt_ops->closesocket(socket);

            new_socket = input_pf->skt_ops->socket(input_pf->family, sock->type, sock->protocol);
            if (new_socket < 0)
            {
                return -1;
            }
            sock->netdev = new_netdev;
            sock->user_data = (void *) new_socket;
        }
    }

    /* check and get protocol families by the network interface device */
    SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, bind);
    return pf->skt_ops->bind((int) sock->user_data, name, namelen);
}

/* lwIP協(xié)議棧函數(shù)底層 bind函數(shù)實(shí)現(xiàn) */

int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
{
 struct lwip_sock *sock;
 ip_addr_t local_addr;
 u16_t local_port;
 err_t err;

 sock = get_socket(s);
 if (!sock) {
    return -1;
 }

 if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
    /* sockaddr does not match socket type (IPv4/IPv6) */
    sock_set_errno(sock, err_to_errno(ERR_VAL));
    return -1;
 }

 /* check size, family and alignment of 'name' */
 LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) &&
             IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)),
             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
 LWIP_UNUSED_ARG(namelen);

 SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port);
 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
 ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));

#if LWIP_IPV4 && LWIP_IPV6
 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
 if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) {
   unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr));
    IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4);
 }
#endif /* LWIP_IPV4 && LWIP_IPV6 */

 err = netconn_bind(sock->conn, &local_addr, local_port);

 if (err != ERR_OK) {
    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
    sock_set_errno(sock, err_to_errno(err));
    return -1;
 }

 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
 sock_set_errno(sock, 0);
 return 0;
}

ART-Pi有兩種常用的聯(lián)網(wǎng)方式,一個(gè)是板載的WiFi模塊AP6212,這個(gè)模塊自帶藍(lán)牙;另一個(gè)是工業(yè)擴(kuò)展板的網(wǎng)口,使用的芯片是LAN8720A。關(guān)于多網(wǎng)卡的使用和自動(dòng)切換在前面的章節(jié)有所講解。本文主要講解如何使用Select/Poll機(jī)制來(lái)實(shí)現(xiàn)并發(fā)服務(wù)器。

RT-Thread網(wǎng)絡(luò)組件:

https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/net/net_introduce

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

    關(guān)注

    13

    文章

    10077

    瀏覽量

    90818
  • RT-Thread
    +關(guān)注

    關(guān)注

    32

    文章

    1534

    瀏覽量

    44223
  • select
    +關(guān)注

    關(guān)注

    0

    文章

    28

    瀏覽量

    4208
  • ART-Pi
    +關(guān)注

    關(guān)注

    0

    文章

    23

    瀏覽量

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

掃碼添加小助手

加入工程師交流群

    評(píng)論

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

    基于Select/Poll實(shí)現(xiàn)并發(fā)服務(wù)器(二)

    LWIP:2.0.2 3 Select/Poll概述 在LWIP中,如果要實(shí)現(xiàn)并發(fā)服務(wù)器,可以基于Sequentaial API來(lái)
    的頭像 發(fā)表于 06-20 00:26 ?6260次閱讀
    基于<b class='flag-5'>Select</b>/<b class='flag-5'>Poll</b><b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>并發(fā)</b><b class='flag-5'>服務(wù)器</b>(二)

    【HZ-RK3568開發(fā)板免費(fèi)體驗(yàn)】基于 Select Poll的TCP發(fā)服務(wù)器

    比較復(fù)雜,本文將基于Select/Poll機(jī)制實(shí)現(xiàn)并發(fā)服務(wù)器。 1 IO模型概述 在具體講解基于Sele
    發(fā)表于 08-19 22:01

    在DragonBoard 410c上實(shí)現(xiàn)并發(fā)處理TCP服務(wù)器

    服務(wù),讓傳感和相關(guān)的控制設(shè)備接入,為此,本期blog將向大家介紹如何使用gevent高性能的并發(fā)處理庫(kù)在draognbaord 410c上來(lái)實(shí)現(xiàn)
    發(fā)表于 09-25 15:53

    高性能高并發(fā)服務(wù)器架構(gòu)分享

    由于自己正在做個(gè)高性能大用戶量的論壇程序,對(duì)高性能高并發(fā)服務(wù)器架構(gòu)比較感興趣,于是在網(wǎng)上收集了不少這方面的資料和大家分享。希望能和大家交流 msn: ——————————————————————————————————————
    發(fā)表于 09-16 06:45

    如何利用多線程去構(gòu)建種TCP并發(fā)服務(wù)器

    、實(shí)驗(yàn)?zāi)康暮鸵?了解TCP/IP協(xié)議2掌握Socket編程,熟悉基于TCP和UDP的傳輸模型3掌握多線程編程4掌握基于TCP的并發(fā)服務(wù)器設(shè)計(jì)二、實(shí)驗(yàn)內(nèi)容和原理實(shí)驗(yàn)內(nèi)容:編寫C程序,利用多線程構(gòu)建
    發(fā)表于 12-22 08:03

    【沁恒微CH32V307評(píng)估板試用體驗(yàn)】基于LWIP實(shí)現(xiàn)并發(fā)服務(wù)器

    程,這是最常用的并發(fā)服務(wù)器設(shè)計(jì)。但是多線程/多進(jìn)程消耗資源多,處理起來(lái)也比較復(fù)雜,本文將基于LWIP協(xié)議棧的Select/Poll機(jī)制實(shí)現(xiàn)
    發(fā)表于 06-01 23:27

    【飛凌嵌入式OK3568-C開發(fā)板試用體驗(yàn)】第4章 基于 Select Poll的TCP發(fā)服務(wù)器

    ,本文將基于Select/Poll機(jī)制實(shí)現(xiàn)并發(fā)服務(wù)器。 4.1 IO模型概述在具體講解基于Select
    發(fā)表于 06-09 22:45

    【原創(chuàng)精選】RT-Thread征文精選技術(shù)文章合集

    。RT-Thread自動(dòng)初始化詳解GD32 RISC-V系列 BSP框架制作與移植GD32407V-START開發(fā)板的BSP框架制作與移植基于Select/Poll實(shí)現(xiàn)并發(fā)
    發(fā)表于 07-26 14:56

    【LuckFox Pico Plus開發(fā)板免費(fèi)試用】基于 Select Poll的TCP發(fā)服務(wù)器

    ,處理起來(lái)也比較復(fù)雜,本文將基于Select/Poll機(jī)制實(shí)現(xiàn)并發(fā)服務(wù)器。 1 IO模型概述 在具體講解基于
    發(fā)表于 10-21 13:31

    Linux環(huán)境并發(fā)服務(wù)器設(shè)計(jì)技術(shù)研究

    講述并發(fā)服務(wù)器設(shè)計(jì)的主要技術(shù),包括多進(jìn)程服務(wù)器、多線程服務(wù)器和I/ O 復(fù)用服務(wù)器,同時(shí)對(duì)以上服務(wù)器
    發(fā)表于 04-24 10:02 ?16次下載

    Linux內(nèi)核中select, poll和epoll的區(qū)別

    先說(shuō)poll,pollselect為大部分Unix/Linux程序員所熟悉,這倆個(gè)東西原理類似,性能上也不存在明顯差異,但select對(duì)所監(jiān)控的文件描述符數(shù)量有限制,所以這里選用
    發(fā)表于 05-14 16:24 ?1991次閱讀

    服務(wù)器的高并發(fā)能力如何提升?

    服務(wù)器的高并發(fā)能力如何提升? 服務(wù)器并發(fā)能力體現(xiàn)著服務(wù)器在單位時(shí)間內(nèi)的很強(qiáng)數(shù)據(jù)處理能力,般來(lái)
    的頭像 發(fā)表于 03-17 17:07 ?1491次閱讀

    網(wǎng)站服務(wù)器并發(fā)數(shù)的計(jì)算方法是什么?

    介紹。 網(wǎng)站服務(wù)器并發(fā)數(shù)主要分為以下幾種:業(yè)務(wù)并發(fā)的用戶數(shù)量、最大的并發(fā)訪問(wèn)數(shù)量、系統(tǒng)中的用戶數(shù)量、同時(shí)在線的用戶數(shù)量。因?yàn)?b class='flag-5'>并發(fā)數(shù)是指網(wǎng)站
    的頭像 發(fā)表于 04-12 15:22 ?4399次閱讀

    并發(fā)服務(wù)器的設(shè)計(jì)與實(shí)現(xiàn)

    并發(fā)服務(wù)器支持多個(gè)客戶端的連接,最大可接入的客戶端數(shù)取決于內(nèi)核控制塊的個(gè)數(shù)。當(dāng)使用Socket API時(shí),要使服務(wù)器能夠同時(shí)支持多個(gè)客戶端的連接,必須引入多任務(wù)機(jī)制,為每個(gè)連接創(chuàng)建個(gè)
    的頭像 發(fā)表于 04-25 15:35 ?1353次閱讀
    <b class='flag-5'>并發(fā)</b><b class='flag-5'>服務(wù)器</b>的設(shè)計(jì)與<b class='flag-5'>實(shí)現(xiàn)</b>

    服務(wù)器并發(fā)的概念

    自己調(diào)整系統(tǒng)的相關(guān)參數(shù) 并發(fā)的概念是什么?什么是并發(fā)? 對(duì)于服務(wù)器并發(fā)的概念,下面幾點(diǎn)是錯(cuò)誤的定義 ①服務(wù)器處理客戶端請(qǐng)求的數(shù)量:沒(méi)有時(shí)間、
    的頭像 發(fā)表于 11-10 10:05 ?8548次閱讀
    <b class='flag-5'>服務(wù)器</b><b class='flag-5'>并發(fā)</b>的概念