導航:首頁 > 編程系統 > recvfromlinux

recvfromlinux

發布時間:2023-04-02 06:02:34

❶ 使用recvfrom接收UDP包在Windows和linux平台的不同表現

操作系統的UDP接收流程如下:收到一個UDP包後,驗證沒有錯誤後,放入一個包隊列中,隊列中的每一個元素就是一個完整的UDP包。當應用程序通過recvfrom()讀取時,OS把相應的一個完整UDP包取出,然後拷貝到用戶提供的內存中,物理用戶提供的內存大小是多少,OS都會完整取出一個UDP包。如果用戶提供的內存小於這個UDP包的大小,那麼在填充慢內存後,UDP包剩餘的部分就會被丟棄,以後再也無法取回。

這與TCP接收完全不同,TCP沒有完整包的概念,也沒有邊界,OS只會取出用戶要求的大小,剩餘的仍然保留在OS中,下次還可以繼續取出。

socket編程雖然是事實上的標准,而且不同平台提供的介面函數也非常類似,但畢竟它不存在嚴格的標准。所以各個平台的實現也不完全兼容。下面就從recvfrom()這個函數看看Window平台和Linux平台的不同。

Windows平台的表現
int
WSAAPI
recvfrom(
_In_ SOCKET s,
_Out_writes_bytes_to_(len, return) __out_data_source(NETWORK) char FAR * buf,
_In_ int len,
_In_ int flags,
_Out_writes_bytes_to_opt_(*fromlen, *fromlen) struct sockaddr FAR * from,
_Inout_opt_ int FAR * fromlen
);

再看MSDN說明:
If the datagram or message is larger than the buffer specified, the buffer is filled with the first part of the datagram, and recvfrom generates the error WSAEMSGSIZE. For unreliable protocols (for example, UDP) the excess data is lost.
可以看出,buf大小小於UDP包大小的時候,recvfrom()會返回-1,並設置錯誤WSAEMSGSIZE。
實際編程測試驗證確實是這樣的表現。

Linux平台的表現
__extern_always_inline ssize_t
recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags,
__SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)

可以看出與Windows平台的函數原型相同。但是在其man手冊里,沒有看到UDP包大於接收緩沖區情況的特殊說明。
代碼測試表明,buf小於UDP包大小的時候,recvfrom()仍然返回復制到緩沖區的位元組數,調用者無法得知UDP包被截斷的情況。

❷ linux Ubuntu 中,寫了一個簡單的UDP協議,只用了sendto 與recvfrom ,出錯了

網路的編輯選項裡面有可以寫代碼的,最起碼代碼格式整齊,容易閱讀。版

客戶端的權serv_addr.sin_addr.s_addr=INADDR_ANY這里使用伺服器的固定地址試試。廣播模式這個地址好像是用255.255.255.0的(區域網下)。

❸ linux手冊翻譯——recv(2)


recv, recvfrom, recvmsg - receive a message from a socket


recv()、recvfrom() 和 recvmsg() 調用用於從套接字接收消息。 它們可用於在UDP和TCP的套接字上接收數據。 本頁首先介紹了所有三個系統調用的共同特點,然後介紹了調用之間的區別。

recv() 和 read(2) 之間的唯一區別是 flags 的存在。 使用腔弊棗零標志參數,recv() 通常等效於 read(2) (但請參閱 NOTES),且
recv(sockfd, buf, len, flags);
等價於
recvfrom(sockfd, buf, len, flags, NULL, NULL);

所有三個調用都在成功完成時返回消息的長度。 如果消息太長而無法放入提供的緩沖區,則 可能 會丟棄多餘的位元組,具體 取決於接收消息的套接字類型 ,顯然TCP是不可能丟棄的。

如果套接字上卜滾沒有可用消息,則接收調用將等待消息到達,除非套接字是非阻塞伍拆的(請參閱 fcntl(2)),在這種情況下,將返回值 -1 並將 errno 設置為 EAGAIN 或 EWOULDBLOCK。 recv_()調用通常會返回任何可用的數據,只要拿到數據就會立馬返回,最多返回指定緩沖區大小的數據,但是並不會等待到讓緩沖區滿 ,除非設置了 MSG_WAITALL 標志,見下。

應用程序可以使用 select(2)、poll(2) 或 epoll(7) 來確定更多數據何時到達。

The flags argument is formed by ORing one or more of the following values:

ee_errno contains the errno number of the queued error. ee_origin is the origin code of where the error originated. The other fields are protocol-specific. The macro SOCK_EE_OFFENDER returns a pointer to the address of the network object where the error originated from given a pointer to the ancillary message. If this address is not known, the sa_family member of the sockaddr contains AF_UNSPEC and the other fields of the sockaddr are undefined. The payload of the packet that caused the error is passed as normal data.
For local errors, no address is passed (this can be checked with the cmsg_len member of the cmsghdr ). For error receives, the MSG_ERRQUEUE flag is set in the msghdr . After an error has been passed, the pending socket error is regenerated based on the next queued error and will be passed on the next socket operation.

recvfrom() 將接收到的消息放入緩沖區 buf 。 調用者必須在 len 中指定緩沖區的大小。

如果調用者希望拿到消息的原地址, 並且底層協議可以提供消息的源地址時,應將 src_addr 設置為指向用於接收消息原地址的緩沖區。 在這種情況下, addrlen 是一個 value-result 參數。 在調用之前,它應該被初始化為與 src_addr 關聯的緩沖區的大小。 返回時,addrlen 被更新以包含源地址的實際大小。 如果提供的緩沖區太小,則截斷返回的地址; 在這種情況下, addrlen 將返回一個大於提供給調用的值。

如果調用者對源地址不感興趣,則應將 src_addr 和 addrlen 指定為 NULL。

ssize_t recv(int sockfd, void* buf, size_t len, int flags);
recv() 調用通常僅用於已連接的套接字(請參閱 connect(2))。 相當於調用:
recvfrom(fd, buf, len, flags, NULL, 0);

ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags);
recvmsg() 調用使用 msghdr 結構來 最小化直接提供的參數數量 。 這個結構在 <sys/socket.h> 中定義如下:

msg_name 欄位指向調用者分配的緩沖區,如果套接字未連接( 特指UDP的服務端 ),則該緩沖區用於返回源地址。 調用者應在此調用之前將 msg_namelen 設置為此緩沖區的大小; 從成功調用返回後,msg_namelen 將包含返回地址的長度。 如果應用程序不需要知道源地址,可以將 msg_name 指定為 NULL。

The fields msg_iov and msg_iovlen describe scatter-gather locations, as discussed in readv(2).
需要注意的是 msg_iov 和 msg_iovlen 描述了一個 struct iovec 類型的數組, msg_iovlen 表示數組的元素個數,而struct iovec則是描述了一個緩沖區

欄位 msg_control 指向用於其他協議控制相關消息或雜項輔助數據的緩沖區。 當recvmsg()被調用時, msg_controllen 為 msg_contro l中可用緩沖區的長度; 從成功調用返回時,它將被設置為控制消息序列的長度。

控制消息的格式為:

只能通過 cmsg(3) 中定義的宏訪問輔助數據。

例如,Linux 使用這種輔助數據機制通過 UNIX 域套接字傳遞擴展錯誤、IP 選項或文件描述符。 有關在各種套接字域中使用輔助數據的更多信息,請參閱 unix(7) 和 ip(7)。

msghdr 中的 msg_flags 欄位在 recvmsg() 返回時設置 。 它可以包含幾個標志:


這些調用返回接收到的位元組數,如果發生錯誤,則返回 -1。 如果發生錯誤,則設置 errno 以指示錯誤。

當流套接字對等端執行有序關閉(orderly shutdown)時,返回值將為 0(傳統的「文件結束」返回)。

各種域(例如 UNIX 和 Internet 域)中的數據報套接字允許零長度數據報。 當收到這樣的數據報時,返回值為 0。

如果從流套接字接收的請求位元組數為 0,則也可能返回值 0。


這些是套接字層生成的一些標准錯誤。 底層協議模塊可能會產生和返回額外的錯誤; 查看他們的手冊頁。


POSIX.1-2001, POSIX.1-2008, 4.4BSD (these interfaces first appeared in 4.2BSD).

POSIX.1 describes only the MSG_OOB, MSG_PEEK, and MSG_WAITALL flags.


如果零長度數據報未決,則帶有零標志參數的 read(2) 和 recv() 提供不同的行為。 在這種情況下, read(2) 不起作用(數據報保持掛起),而 recv() 消耗掛起的數據報。

socklen_t 類型是由 POSIX 發明的。 另見 accept(2) 。

根據 POSIX.1,msghdr 結構的 msg_controllen 欄位類型為 socklen_t,而 msg_iovlen 欄位類型為 int,但 glibc 目前將兩者設置為 size_t。

有關可用於在單個調用中接收多個數據報的 Linux 特定系統調用的信息,請參閱 recvmmsg(2)。


getaddrinfo(3) 中顯示了使用 recv() 的示例。

❹ linux下socket文件傳輸問題

如果你的客戶端在發送文件時,每次都重新connect,再進行數據傳輸,則你的程序無回法解決數據的區分。答
如果客戶端是一次connect循環發送,後台服務循環接收,則
(1)如果你的服務端只有一個進程(不支持並發),則A和B不會同時運行,只能按順序接收完A再接收B
(2)如果,每一個新鏈接上來,你都建立一個新的進程去工作,則不會有問題。

❺ Linux系統I/O模型及select、poll、epoll原理和應用

理解Linux的IO模型之前,首先要了解一些基本概念,才能理解這些IO模型設計的依據

操作系統使用虛擬內存來映射物理內存,對於32位的操作系統來說,虛擬地址空間為4G(2^32)。操作系統的核心是內核,為了保護用戶進程不能直接操作內核,保證內核安全,操作系統將虛擬地址空間劃分為內核空間和用戶空間。內核可以訪問全部的地址空間,擁有訪問底層硬體設備的許可權,普通的應用程序需要訪問硬體設備必須通過 系統調用 來實現。

對於Linux系統來說,將虛擬內存的最高1G位元組的空間作為內核空間僅供內核使用,低3G位元組的空間供用戶進程使用,稱為用戶空間。

又被稱為標准I/O,大多數文件系統的默認I/O都是緩存I/O。在Linux系統的緩存I/O機制中,操作系統會將I/O的數據緩存在頁緩存(內存)中,也就是數據先被拷貝到內核的緩沖區(內核地址空間),然後才會從內核緩沖區拷貝到應用程序的緩沖區(用戶地址空間)。

這種方式很明顯的缺點就是數據傳輸過程中需要再應用程序地址空間和內核空間進行多次數據拷貝操作,這些操作帶來的CPU以及內存的開銷是非常大的。

由於Linux系統採用的緩存I/O模式,對於一次I/O訪問,以讀操作舉例,數據先會被拷貝到內核緩沖區,然後才會從內核緩沖區拷貝到應用程序的緩存區,當一個read系統調用發生的時候,會經歷兩個階段:

正是因為這兩個狀態,Linux系統才產生了多種不同的網路I/O模式的方案

Linux系統默認情況下所有socke都是blocking的,一個讀操作流程如下:

以UDP socket為例,當用戶進程調用了recvfrom系統調用,如果數據還沒准備好,應用進程被阻塞,內核直到數據到來且將數據從內核緩沖區拷貝到了應用進程緩沖區,然後向用戶進程返回結果,用戶進程才解除block狀態,重新運行起來。

阻塞模行下只是阻塞了當前的應用進程,其他進程還可以執行,不消耗CPU時間,CPU的利用率較高。

Linux可以設置socket為非阻塞的,非阻塞模式下執行一個讀操作流程如下:

當用戶進程發出recvfrom系統調用時,如果kernel中的數據還沒准備好,recvfrom會立即返回一個error結果,不會阻塞用戶進程,用戶進程收到error時知道數據還沒准備好,過一會再調用recvfrom,直到kernel中的數據准備好了,內核就立即將數據拷貝到用戶內存然後返回ok,這個過程需要用戶進程去輪詢內核數據是否准備好。

非阻塞模型下由於要處理更多的系統調用,因此CPU利用率比較低。

應用進程使用sigaction系統調用,內核立即返回,等到kernel數據准備好時會給用戶進程發送一個信號,告訴用戶進程可以進行IO操作了,然後用戶進程再調用IO系統調用如recvfrom,將數據從內核緩沖區拷貝到應用進程。流程如下:

相比於輪詢的方式,不需要多次系統調用輪詢,信號驅動IO的CPU利用率更高。

非同步IO模型與其他模型最大的區別是,非同步IO在系統調用返回的時候所有操作都已經完成,應用進程既不需要等待數據准備,也不需要在數據到來後等待數據從內核緩沖區拷貝到用戶緩沖區,流程如下:

在數據拷貝完成後,kernel會給用戶進程發送一個信號告訴其read操作完成了。

是用select、poll等待數據,可以等待多個socket中的任一個變為可讀,這一過程會被阻塞,當某個套接字數據到來時返回,之後再用recvfrom系統調用把數據從內核緩存區復制到用戶進程,流程如下:

流程類似阻塞IO,甚至比阻塞IO更差,多使用了一個系統調用,但是IO多路復用最大的特點是讓單個進程能同時處理多個IO事件的能力,又被稱為事件驅動IO,相比於多線程模型,IO復用模型不需要線程的創建、切換、銷毀,系統開銷更小,適合高並發的場景。

select是IO多路復用模型的一種實現,當select函數返回後可以通過輪詢fdset來找到就緒的socket。

優點是幾乎所有平台都支持,缺點在於能夠監聽的fd數量有限,Linux系統上一般為1024,是寫死在宏定義中的,要修改需要重新編譯內核。而且每次都要把所有的fd在用戶空間和內核空間拷貝,這個操作是比較耗時的。

poll和select基本相同,不同的是poll沒有最大fd數量限制(實際也會受到物理資源的限制,因為系統的fd數量是有限的),而且提供了更多的時間類型。

總結:select和poll都需要在返回後通過輪詢的方式檢查就緒的socket,事實上同時連的大量socket在一個時刻只有很少的處於就緒狀態,因此隨著監視的描述符數量的變多,其性能也會逐漸下降。

epoll是select和poll的改進版本,更加靈活,沒有描述符限制。epoll使用一個文件描述符管理多個描述符,將用戶關系的文件描述符的事件存放到內核的一個事件表中,這樣在用戶空間和內核空間的只需一次。

epoll_create()用來創建一個epoll句柄。
epoll_ctl() 用於向內核注冊新的描述符或者是改變某個文件描述符的狀態。已注冊的描述符在內核中會被維護在一棵紅黑樹上,通過回調函數內核會將 I/O 准備好的描述符加入到一個就緒鏈表中管理。
epoll_wait() 可以從就緒鏈表中得到事件完成的描述符,因此進程不需要通過輪詢來獲得事件完成的描述符。

當epoll_wait檢測到描述符IO事件發生並且通知給應用程序時,應用程序可以不立即處理該事件,下次調用epoll_wait還會再次通知該事件,支持block和nonblocking socket。

當epoll_wait檢測到描述符IO事件發生並且通知給應用程序時,應用程序需要立即處理該事件,如果不立即處理,下次調用epoll_wait不會再次通知該事件。

ET模式在很大程度上減少了epoll事件被重復觸發的次數,因此效率要比LT模式高。epoll工作在ET模式的時候,必須使用nonblocking socket,以避免由於一個文件句柄的阻塞讀/阻塞寫操作把處理多個文件描述符的任務餓死。

【segmentfault】 Linux IO模式及 select、poll、epoll詳解
【GitHub】 CyC2018/CS-Notes

❻ Linux網路 - 數據包在內核中接收和發送的過程(轉)

本文將介紹在Linux系統中, 數據包是如何一步一步從網卡傳到進程手中的 以及 數據包是如何一步一步從應用程序到網卡並最終發送出去的

如果英文沒有問題,強烈建議閱讀後面參考里的文章,裡面介紹的更詳細。

本文只討論乙太網的物理網卡,不涉及虛擬設備,並且以一個UDP包的接收過程作為示例.

網卡需要有驅動才能工作,驅動是載入到內核中的模塊,負責銜接網卡和內核的網路模塊,驅動在載入的時候將自己注冊進網路模塊,當相應的網卡收到數據包時,網路模塊會調用相應的驅動程序處理數據。

下圖展示了數據包(packet)如何進入內存,並被內核的網路模塊開始處理:

軟中斷會觸發內核網路模塊中的軟中斷處理函數,後續流程如下

由於是UDP包,所以第一步會進入IP層,然後一級一級的函數往下調:

應用層一般有兩種方式接收數據,一種是recvfrom函數阻塞在那裡等著數據來,這種情況下當socket收到通知後,recvfrom就會被喚醒,然後讀取接收隊列的數據;另一種是通過epoll或者select監聽相應的socket,當收到通知後,再調用recvfrom函數去讀取接收隊列的數據。兩種情況都能正常的接收到相應的數據包。

了解數據包的接收流程有助於幫助我們搞清楚我們可以在哪些地方監控和修改數據包,哪些情況下數據包可能被丟棄,為我們處理網路問題提供了一些參考,同時了解netfilter中相應鉤子的位置,對於了解iptables的用法有一定的幫助,同時也會幫助我們後續更好的理解Linux下的網路虛擬設備。

ndo_start_xmit會綁定到具體網卡驅動的相應函數,到這步之後,就歸網卡驅動管了,不同的網卡驅動有不同的處理方式,這里不做詳細介紹,其大概流程如下:

在網卡驅動發送數據包過程中,會有一些地方需要和netdevice子系統打交道,比如網卡的隊列滿了,需要告訴上層不要再發了,等隊列有空閑的時候,再通知上層接著發數據。

❼ linux下設置recvfrom為非阻塞

可以使用
1 select pselect
2 poll

3可以使用fcntl給文件描述符添加O—UNBLOCK

❽ Linux下的recvfrom為什麼一直阻塞

UDP的client端是需要bind的,server端不需要bind,

關於阻塞的問題,應該在於你的socket的屬性,設置成O_NONBLOCK就可以了。

❾ linux網路編程中 如何退出接受數據等待。。。recv recvfrom。。。

先用select或者poll或者epoll對你的socket進行監聽...
上面幾個API都可以設置超時時間,時間比較精確.
他們的作用都是監聽文件描述符上的事件(可讀,可寫等等),你的sockfd也是一個文件描述符...

具體用法自己查吧...

❿ linux用udp協議時,為什麼recefrom函數會卡住

數據包丟失。
如果數據包在傳輸中丟失,recvfrom函數將會一直阻塞,直到謹彎運祥梁超時或者重新發送數據包鬧螞。
UDP(UserDatagramProtocol)是一種無連接的、不可靠的傳輸層協議。UDP協議是網際網路傳輸協議族中的一員,和TCP協議一樣都處於傳輸層。

閱讀全文

與recvfromlinux相關的資料

熱點內容
maya粒子表達式教程 瀏覽:84
抖音小視頻如何掛app 瀏覽:283
cad怎麼設置替補文件 瀏覽:790
win10啟動文件是空的 瀏覽:397
jk網站有哪些 瀏覽:134
學編程和3d哪個更好 瀏覽:932
win10移動硬碟文件無法打開 瀏覽:385
文件名是亂碼還刪不掉 瀏覽:643
蘋果鍵盤怎麼打開任務管理器 瀏覽:437
手機桌面文件名字大全 瀏覽:334
tplink默認無線密碼是多少 瀏覽:33
ipaddgm文件 瀏覽:99
lua語言編程用哪個平台 瀏覽:272
政采雲如何導出pdf投標文件 瀏覽:529
php獲取postjson數據 瀏覽:551
javatimetask 瀏覽:16
編程的話要什麼證件 瀏覽:94
錢脈通微信多開 瀏覽:878
中學生學編程哪個培訓機構好 瀏覽:852
榮耀路由TV設置文件共享錯誤 瀏覽:525

友情鏈接