導航:首頁 > 編程語言 > linuxudp網路編程

linuxudp網路編程

發布時間:2022-12-22 07:56:31

『壹』 純軟體開發人員怎樣做嵌入式linux應用開發

二:Linux基礎 Linux操作系統的概念、安裝方法,詳細了解Linux下的目錄結構、基本命令、編輯器VI ,編譯器GCC,調試器GDB和 Make 項目管理工具, Shell Makefile腳本編寫等知識,嵌入式開發環境的搭建。
三:Linux系統編程 重點學習標准I/O庫,Linux多任務編程中的多進程和多線程,以及進程間通信(pipe、FIFO、消息隊列、共享內存、signal、信號量等),同步與互斥對共享資源訪問控制等重要知識,主要提升對Linux應用開發的理解和代碼調試的能力。
四:Linux網路編程 計算機網路在嵌入式Linux系統應用開發過程中使用非常廣泛,通過Linux網路發展、TCP/IP協議、socket編程、TCP網路編程、UDP網路編程、Web編程開發等方面入手,全面了解Linux網路應用程序開發。重點學習網路編程相關API,熟練掌握TCP協議伺服器的編程方法和並發伺服器的實現,了解HTTP協議及其實現方法,熟悉UDP廣播、多播的原理及編程方法,掌握混合C/S架構網路通信系統的設計,熟悉HTML,Javascript等Web編程技術及實現方法。
五:數據結構與演算法 數據結構及演算法在嵌入式底層驅動、通信協議、及各種引擎開發中會得到大量應用,對其掌握的好壞直接影響程序的效率、簡潔及健壯性。此階段的學習要重點理解數據結構與演算法的基礎內容,包括順序表、鏈表、隊列、棧、樹、圖、哈希表、各種查找排序演算法等應用及其C語言實現過程。

『貳』 linux c語言實現,udp協議

UDP協議全稱是用戶數據報協議,在網路中它與TCP協議一樣用於處理數據包,是一種無連接的協議。在OSI模型中,在第四層--傳輸層,處於IP協議的上一層。UDP有不提供數據包分組、組裝和不能對數據包進行排序的缺點,也就是說,當報文發送之後,是無法得知其是否安全完整到達的。UDP用來支持那些需要在計算機之間傳輸數據的網路應用。包括網路視頻會議系統在內的眾多的客戶/伺服器模式的網路應用都需要使用UDP協議。UDP協議從問世至今已經被使用了很多年,雖然其最初的光彩已經被一些類似協議所掩蓋,但是即使是在今天UDP仍然不失為一項非常實用和可行的網路傳輸層協議。

『叄』 在Linux 上,編寫一個每秒接收 100萬UDP數據包的程序究竟有多難

首先,我們假設:
測量每秒的數據包(pps)比測量每秒位元組數(Bps)更有意思。您可以通過更好的管道輸送以及發送更長數據包來獲取更高的Bps。而相比之下,提高pps要困難得多。
因為我們對pps感興趣,我們的實驗將使用較短的 UDP 消息。准確來說是 32 位元組的 UDP 負載,這相當於乙太網層的 74 位元組。
在實驗中,我們將使用兩個物理伺服器:「接收器」和「發送器」。
它們都有兩個六核2 GHz的 Xeon處理器。每個伺服器都啟用了 24 個處理器的超線程(HT),有 Solarflare 的 10G 多隊列網卡,有 11 個接收隊列配置。稍後將詳細介紹。
測試程序的源代碼分別是:udpsender、udpreceiver。
預備知識
我們使用4321作為UDP數據包的埠,在開始之前,我們必須確保傳輸不會被iptables干擾:

Shell

receiver$ iptables -I INPUT 1 -p udp --dport 4321 -j ACCEPT

receiver$ iptables -t raw -I PREROUTING 1 -p udp --dport 4321 -j NOTRACK

為了後面測試方便,我們顯式地定義IP地址:

Shell

receiver$ for i in `seq 1 20`; do

ip addr add 192.168.254.$i/24 dev eth2;

done

sender$ ip addr add 192.168.254.30/24 dev eth3

1. 簡單的方法
開始我們做一些最簡單的試驗。通過簡單地發送和接收,有多少包將會被傳送?
模擬發送者的偽代碼:

Python

fd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

fd.bind(("0.0.0.0", 65400)) # select source port to rece nondeterminism

fd.connect(("192.168.254.1", 4321))

while True:

fd.sendmmsg(["x00" * 32] * 1024)

因為我們使用了常見的系統調用的send,所以效率不會很高。上下文切換到內核代價很高所以最好避免它。幸運地是,最近Linux加入了一個方便的系統調用叫sendmmsg。它允許我們在一次調用時,發送很多的數據包。那我們就一次發1024個數據包。
模擬接受者的偽代碼:

Python

fd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
fd.bind(("0.0.0.0", 4321))
while True:
packets = [None] * 1024
fd.recvmmsg(packets, MSG_WAITFORONE)

同樣地,recvmmsg 也是相對於常見的 recv 更有效的一版系統調用。
讓我們試試吧:

Shell

sender$ ./udpsender 192.168.254.1:4321
receiver$ ./udpreceiver1 0.0.0.0:4321
0.352M pps 10.730MiB / 90.010Mb
0.284M pps 8.655MiB / 72.603Mb
0.262M pps 7.991MiB / 67.033Mb
0.199M pps 6.081MiB / 51.013Mb
0.195M pps 5.956MiB / 49.966Mb
0.199M pps 6.060MiB / 50.836Mb
0.200M pps 6.097MiB / 51.147Mb
0.197M pps 6.021MiB / 50.509Mb

測試發現,運用最簡單的方式可以實現 197k – 350k pps。看起來還不錯嘛,但不幸的是,很不穩定啊,這是因為內核在核之間交換我們的程序,那我們把進程附在 CPU 上將會有所幫助

Shell

sender$ taskset -c 1 ./udpsender 192.168.254.1:4321
receiver$ taskset -c 1 ./udpreceiver1 0.0.0.0:4321
0.362M pps 11.058MiB / 92.760Mb
0.374M pps 11.411MiB / 95.723Mb
0.369M pps 11.252MiB / 94.389Mb
0.370M pps 11.289MiB / 94.696Mb
0.365M pps 11.152MiB / 93.552Mb
0.360M pps 10.971MiB / 92.033Mb

現在內核調度器將進程運行在特定的CPU上,這提高了處理器緩存,使數據更加一致,這就是我們想要的啊!
2. 發送更多的數據包
雖然 370k pps 對於簡單的程序來說已經很不錯了,但是離我們 1Mpps 的目標還有些距離。為了接收更多,首先我們必須發送更多的包。那我們用獨立的兩個線程發送,如何呢:

Shell

sender$ taskset -c 1,2 ./udpsender
192.168.254.1:4321 192.168.254.1:4321
receiver$ taskset -c 1 ./udpreceiver1 0.0.0.0:4321
0.349M pps 10.651MiB / 89.343Mb
0.354M pps 10.815MiB / 90.724Mb
0.354M pps 10.806MiB / 90.646Mb
0.354M pps 10.811MiB / 90.690Mb

接收一端的數據沒有增加,ethtool –S 命令將顯示數據包實際上都去哪兒了:

Shell

receiver$ watch 'sudo ethtool -S eth2 |grep rx'
rx_nodesc_drop_cnt: 451.3k/s
rx-0.rx_packets: 8.0/s
rx-1.rx_packets: 0.0/s
rx-2.rx_packets: 0.0/s
rx-3.rx_packets: 0.5/s
rx-4.rx_packets: 355.2k/s
rx-5.rx_packets: 0.0/s
rx-6.rx_packets: 0.0/s
rx-7.rx_packets: 0.5/s
rx-8.rx_packets: 0.0/s
rx-9.rx_packets: 0.0/s
rx-10.rx_packets: 0.0/s

通過這些統計,NIC 顯示 4 號 RX 隊列已經成功地傳輸大約 350Kpps。rx_nodesc_drop_cnt 是 Solarflare 特有的計數器,表明NIC發送到內核未能實現發送 450kpps。
有時候,這些數據包沒有被發送的原因不是很清晰,然而在我們這種情境下卻很清楚:4號RX隊列發送數據包到4號CPU,然而4號CPU已經忙不過來了,因為它最忙也只能讀350kpps。在htop中顯示為:

多隊列 NIC 速成課程
從歷史上看,網卡擁有單個RX隊列,用於硬體和內核之間傳遞數據包。這樣的設計有一個明顯的限制,就是不可能比單個CPU處理更多的數據包。
為了利用多核系統,NIC開始支持多個RX隊列。這種設計很簡單:每個RX隊列被附到分開的CPU上,因此,把包送到所有的RX隊列網卡可以利用所有的CPU。但是又產生了另一個問題:對於一個數據包,NIC怎麼決定把它發送到哪一個RX隊列?

用 Round-robin 的方式來平衡是不能接受的,因為這有可能導致單個連接中數據包的重排序。另一種方法是使用數據包的hash值來決定RX號碼。Hash值通常由一個元組(源IP,目標IP,源port,目標port)計算而來。這確保了從一個流產生的包將最終在完全相同的RX隊列,並且不可能在一個流中重排包。
在我們的例子中,hash值可能是這樣的:

Shell

1

RX_queue_number = hash('192.168.254.30', '192.168.254.1', 65400, 4321) % number_of_queues

多隊列 hash 演算法
Hash演算法通過ethtool配置,設置如下:

Shell

receiver$ ethtool -n eth2 rx-flow-hash udp4
UDP over IPV4 flows use these fields for computing Hash flow key:
IP SA
IP DA

對於IPv4 UDP數據包,NIC將hash(源 IP,目標 IP)地址。即

Shell

1

RX_queue_number = hash('192.168.254.30', '192.168.254.1') % number_of_queues

這是相當有限的,因為它忽略了埠號。很多NIC允許自定義hash。再一次,使用ethtool我們可以選擇元組(源 IP、目標 IP、源port、目標port)生成hash值。

Shell

receiver$ ethtool -N eth2 rx-flow-hash udp4 sdfn
Cannot change RX network flow hashing options: Operation not supported

不幸地是,我們的NIC不支持自定義,我們只能選用(源 IP、目的 IP) 生成hash。
NUMA性能報告
到目前為止,我們所有的數據包都流向一個RX隊列,並且一個CPU。我們可以借這個機會為基準來衡量不同CPU的性能。在我們設置為接收方的主機上有兩個單獨的處理器,每一個都是一個不同的NUMA節點。
在我們設置中,可以將單線程接收者依附到四個CPU中的一個,四個選項如下:
另一個CPU上運行接收器,但將相同的NUMA節點作為RX隊列。性能如上面我們看到的,大約是360 kpps。
將運行接收器的同一 CPU 作為RX隊列,我們可以得到大約430 kpps。但這樣也會有很高的不穩定性,如果NIC被數據包所淹沒,性能將下降到零。
當接收器運行在HT對應的處理RX隊列的CPU之上,性能是通常的一半,大約在200kpps左右。
接收器在一個不同的NUMA節點而不是RX隊列的CPU上,性能大約是330 kpps。但是數字會不太一致。
雖然運行在一個不同的NUMA節點上有10%的代價,聽起來可能不算太壞,但隨著規模的變大,問題只會變得更糟。在一些測試中,每個核只能發出250 kpps,在所有跨NUMA測試中,這種不穩定是很糟糕。跨NUMA節點的性能損失,在更高的吞吐量上更明顯。在一次測試時,發現在一個壞掉的NUMA節點上運行接收器,性能下降有4倍。
3.多接收IP
因為我們NIC上hash演算法的限制,通過RX隊列分配數據包的唯一方法是利用多個IP地址。下面是如何將數據包發到不同的目的IP:

1

sender$ taskset -c 1,2 ./udpsender 192.168.254.1:4321 192.168.254.2:4321

ethtool 證實了數據包流向了不同的 RX 隊列:

Shell

receiver$ watch 'sudo ethtool -S eth2 |grep rx'
rx-0.rx_packets: 8.0/s
rx-1.rx_packets: 0.0/s
rx-2.rx_packets: 0.0/s
rx-3.rx_packets: 355.2k/s
rx-4.rx_packets: 0.5/s
rx-5.rx_packets: 297.0k/s
rx-6.rx_packets: 0.0/s
rx-7.rx_packets: 0.5/s
rx-8.rx_packets: 0.0/s
rx-9.rx_packets: 0.0/s
rx-10.rx_packets: 0.0/s

接收部分:

Shell

receiver$ taskset -c 1 ./udpreceiver1 0.0.0.0:4321
0.609M pps 18.599MiB / 156.019Mb
0.657M pps 20.039MiB / 168.102Mb
0.649M pps 19.803MiB / 166.120Mb

萬歲!有兩個核忙於處理RX隊列,第三運行應用程序時,可以達到大約650 kpps !
我們可以通過發送數據到三或四個RX隊列來增加這個數值,但是很快這個應用就會有另一個瓶頸。這一次rx_nodesc_drop_cnt沒有增加,但是netstat接收到了如下錯誤:

Shell

receiver$ watch 'netstat -s --udp'
Udp:
437.0k/s packets received
0.0/s packets to unknown port received.
386.9k/s packet receive errors
0.0/s packets sent
RcvbufErrors: 123.8k/s
SndbufErrors: 0
InCsumErrors: 0

這意味著雖然NIC能夠將數據包發送到內核,但是內核不能將數據包發給應用程序。在我們的case中,只能提供440 kpps,其餘的390 kpps + 123 kpps的下降是由於應用程序接收它們不夠快。
4.多線程接收
我們需要擴展接收者應用程序。最簡單的方式是利用多線程接收,但是不管用:

Shell

sender$ taskset -c 1,2 ./udpsender 192.168.254.1:4321 192.168.254.2:4321
receiver$ taskset -c 1,2 ./udpreceiver1 0.0.0.0:4321 2
0.495M pps 15.108MiB / 126.733Mb
0.480M pps 14.636MiB / 122.775Mb
0.461M pps 14.071MiB / 118.038Mb
0.486M pps 14.820MiB / 124.322Mb

接收性能較於單個線程下降了,這是由UDP接收緩沖區那邊的鎖競爭導致的。由於兩個線程使用相同的套接字描述符,它們花費過多的時間在UDP接收緩沖區的鎖競爭。這篇論文詳細描述了這一問題。
看來使用多線程從一個描述符接收,並不是最優方案。
5. SO_REUSEPORT
幸運地是,最近有一個解決方案添加到 Linux 了 —— SO_REUSEPORT 標志位(flag)。當這個標志位設置在一個套接字描述符上時,Linux將允許許多進程綁定到相同的埠,事實上,任何數量的進程將允許綁定上去,負載也會均衡分布。
有了SO_REUSEPORT,每一個進程都有一個獨立的socket描述符。因此每一個都會擁有一個專用的UDP接收緩沖區。這樣就避免了以前遇到的競爭問題:

Shell

1
2
3
4

receiver$ taskset -c 1,2,3,4 ./udpreceiver1 0.0.0.0:4321 4 1
1.114M pps 34.007MiB / 285.271Mb
1.147M pps 34.990MiB / 293.518Mb
1.126M pps 34.374MiB / 288.354Mb

現在更加喜歡了,吞吐量很不錯嘛!
更多的調查顯示還有進一步改進的空間。即使我們開始4個接收線程,負載也會不均勻地分布:

兩個進程接收了所有的工作,而另外兩個根本沒有數據包。這是因為hash沖突,但是這次是在SO_REUSEPORT層。
結束語
我做了一些進一步的測試,完全一致的RX隊列,接收線程在單個NUMA節點可以達到1.4Mpps。在不同的NUMA節點上運行接收者會導致這個數字做多下降到1Mpps。
總之,如果你想要一個完美的性能,你需要做下面這些:
確保流量均勻分布在許多RX隊列和SO_REUSEPORT進程上。在實踐中,只要有大量的連接(或流動),負載通常是分布式的。
需要有足夠的CPU容量去從內核上獲取數據包。
To make the things harder, both RX queues and receiver processes should be on a single NUMA node.
為了使事情更加穩定,RX隊列和接收進程都應該在單個NUMA節點上。
雖然我們已經表明,在一台Linux機器上接收1Mpps在技術上是可行的,但是應用程序將不會對收到的數據包做任何實際處理——甚至連看都不看內容的流量。別太指望這樣的性能,因為對於任何實際應用並沒有太大用處。

『肆』 linux系統編程和網路編程的區別

如果是學習使用是很簡單的,知道提供什麼介面,如何調用就行了。 如果是學習原來則需要有一些操作系統知識、網路基礎知識、TCP/UDP協議基礎知識。線程知識當然是必須的。

『伍』 linux下udp編程如何同時獲取源IP和埠及目的IP和埠

http://www.cnblogs.com/kissazi2/p/3158603.html

『陸』 linux系統網路編程主要是學什麼要用到哪些概念和函數最好是舉例說明,要詳細些

多線程和多進程要學。socket套接字要學。TCP/UDP也要學。這些是基本肯定要學的吧,其餘的就不知道你們研究多深了。用到的函數太多了- -!而且函數的參數也多的一筆,很難記的,有幫助手冊了還好。

閱讀全文

與linuxudp網路編程相關的資料

熱點內容
dvd光碟存儲漢子演算法 瀏覽:757
蘋果郵件無法連接伺服器地址 瀏覽:963
phpffmpeg轉碼 瀏覽:671
長沙好玩的解壓項目 瀏覽:145
專屬學情分析報告是什麼app 瀏覽:564
php工程部署 瀏覽:833
android全屏透明 瀏覽:737
阿里雲伺服器已開通怎麼辦 瀏覽:803
光遇為什麼登錄時伺服器已滿 瀏覽:302
PDF分析 瀏覽:485
h3c光纖全工半全工設置命令 瀏覽:143
公司法pdf下載 瀏覽:382
linuxmarkdown 瀏覽:350
華為手機怎麼多選文件夾 瀏覽:683
如何取消命令方塊指令 瀏覽:349
風翼app為什麼進不去了 瀏覽:778
im4java壓縮圖片 瀏覽:362
數據查詢網站源碼 瀏覽:150
伊克塞爾文檔怎麼進行加密 瀏覽:892
app轉賬是什麼 瀏覽:163