1. 程式人生 > >UDP協議的兩個主要方法sendto和recvfrom詳解

UDP協議的兩個主要方法sendto和recvfrom詳解

sendto()簡述:
  向一指定目的地傳送資料。

  #include <winsock.h>

  int PASCAL FAR sendto( SOCKET s, const char FAR* buf, int len, int flags,
  const struct sockaddr FAR* to, int tolen);

  s:一個標識套介面的描述字。
  buf:包含待發送資料的緩衝區。
  len:buf緩衝區中資料的長度。
  flags:呼叫方式標誌位。
  to:(可選)指標,指向目的套介面的地址。
  tolen:to所指地址的長度。

註釋:
  sendto()適用於已連線的資料報或流式套介面傳送資料。對於資料報類套介面,必需注意傳送資料長度不應超過通訊子網的IP包最大長度。IP包最大長度在WSAStartup()呼叫返回的WSAData的iMaxUdpDg元素中。如果資料太長無法自動通過下層協議,則返回WSAEMSGSIZE錯誤,資料不會被髮送。
  請注意成功地完成sendto()呼叫並不意味著資料傳送到達。
  sendto()函式主要用於SOCK_DGRAM型別套介面向to引數指定端的套介面傳送資料報。對於SOCK_STREAM型別套介面,to和tolen引數被忽略;這種情況下sendto()等價於send()。
  為了傳送廣播資料(僅適用於SOCK_DGRAM),in引數所含地址應該把特定的IP地址INADDR_BROADCAST(winsock.h中有定義)和終端地址結合起來構造。通常建議一個廣播資料報的大小不要大到以致產生碎片,也就是說資料報的資料部分(包括頭)不超過512位元組。
  如果傳送系統的緩衝區空間不夠儲存需傳送的資料,除非套介面處於非阻塞I/O方式,否則sendto()將阻塞。對於非阻塞SOCK_STREAM型別的套介面,實際寫的資料數目可能在1到所需大小之間,其值取決於本地和遠端主機的緩衝區大小。可用select()呼叫來確定何時能夠進一步傳送資料。
  在相關套介面的選項之上,還可通過標誌位flag來影響函式的執行方式。也就是說,本函式的語義既取決於套介面的選項也取決於標誌位。後者由以下一些值組成:

值      意義
MSG_DONTROUTE   指明資料不選徑。一個WINDOWS套介面供應商可以忽略此標誌;參見2.4節中關於SO_DONTROUTE的討論。
MSG_OOB     傳送帶外資料(僅適用於SO_STREAM;參見2.2.3節)。 

返回值:
  若無錯誤發生,send()返回所傳送資料的總數(請注意這個數字可能小於len中所規定的大小)。否則的話,返回SOCKET_ERROR錯誤,應用程式可通過WSAGetLastError()獲取相應錯誤程式碼。
 
recvfrom()簡述:
  接收一個數據報並儲存源地址。

  #include <winsock.h>

  int PASCAL FAR recvfrom( SOCKET s, char FAR* buf, int len, int flags,
  struct sockaddr FAR* from, int FAR* fromlen);

  s:標識一個已連線套介面的描述字。
  buf:接收資料緩衝區。
  len:緩衝區長度。
  flags:呼叫操作方式。
  from:(可選)指標,指向裝有源地址的緩衝區。
  fromlen:(可選)指標,指向from緩衝區長度值。

註釋:
  本函式由於從(已連線)套介面上接收資料,並捕獲資料傳送源的地址。
  對於SOCK_STREAM型別的套介面,最多可接收緩衝區大小個資料。如果套介面被設定為線內接收帶外資料(選項為SO_OOBINLINE),且有帶外資料未讀入,則返回帶外資料。應用程式可通過呼叫ioctlsocket()的SOCATMARK命令來確定是否有帶外資料待讀入。對於SOCK_STREAM型別套介面,忽略from和fromlen引數。
  對於資料報類套介面,佇列中第一個資料報中的資料被解包,但最多不超過緩衝區的大小。如果資料報大於緩衝區,那麼緩衝區中只有資料報的前面部分,其他的資料都丟失了,並且recvfrom()函式返回WSAEMSGSIZE錯誤。
  若from非零,且套介面為SOCK_DGRAM型別,則傳送資料來源的地址被複制到相應的sockaddr結構中。fromlen所指向的值初始化時為這個結構的大小,當呼叫返回時按實際地址所佔的空間進行修改。
  如果沒有資料待讀,那麼除非是非阻塞模式,不然的話套介面將一直等待資料的到來,此時將返回SOCKET_ERROR錯誤,錯誤程式碼是WSAEWOULDBLOCK。用select()或WSAAsynSelect()可以獲知何時資料到達。
  如果套介面為SOCK_STREAM型別,並且遠端“優雅”地中止了連線,那麼recvfrom()一個數據也不讀取,立即返回。如果立即被強制中止,那麼recv()將以WSAECONNRESET錯誤失敗返回。
  在套介面的所設選項之上,還可用標誌位flag來影響函式的執行方式。也就是說,本函式的語義既取決於套介面選項,也取決於標誌位引數。標誌位可取下列值:
  值 意義
  MSG_PEEK 檢視當前資料。資料將被複制到緩衝區中,但並不從輸入佇列中刪除。
  MSG_OOB 處理帶外資料(參見2.2.3節具體討論)。
 
返回值:
  若無錯誤發生,recvfrom()返回讀入的位元組數。如果連線已中止,返回0。否則的話,返回SOCKET_ERROR錯誤,應用程式可通過WSAGetLastError()獲取相應錯誤程式碼。


錯誤程式碼:
  WSANOTINITIALISED:在使用此API之前應首先成功地呼叫WSAStartup()。
  WSAENETDOWN:WINDOWS套介面實現檢測到網路子系統失效。
  WSAEFAULT:fromlen引數非法;from緩衝區大小無法裝入端地址。
  WSAEINTR:阻塞程序被WSACancelBlockingCall()取消。
  WSAEINPROGRESS:一個阻塞的WINDOWS套介面呼叫正在執行中。
  WSAEINVAL:套介面未用bind()進行捆綁。
  WSAENOTCONN:套介面未連線(僅適用於SOCK_STREAM型別)。
  WSAENOTSOCK:描述字不是一個套介面。
  WSAEOPNOTSUPP:指定了MSG_OOB,但套介面不是SOCK_STREAM型別的。
  WSAESHUTDOWN:套介面已被關閉。當一個套介面以0或2的how引數呼叫shutdown()關閉後,無法再用recv()接收資料。
  WSAEWOULDBLOCK:套介面標識為非阻塞模式,但接收操作會產生阻塞。
  WSAEMSGSIZE:資料報太大無法全部裝入緩衝區,故被剪下。
  WSAECONNABORTED:由於超時或其他原因,虛電路失效。
  WSAECONNRESET:遠端強制中止了虛電路。