.7.3.3 數據傳輸
收發數據是網絡編程的主題。要在已建立連接的套接字上接收數據,可用這兩個A P I函數:
s e n d和W S A S e n d。第二個函數是Winsock 2中專有的。同樣地,在已建立了連接的套接字上接收數據也有兩個函數: r e c v和W S A R e c v。后者也是Winsock 2函數。
必須牢牢記住這一點:所有關系到收發數據的緩沖都屬于簡單的c h a r類型。也就是說,這些函數沒有“U n i c o d e”版本。
另外,所有收發函數返回的錯誤代碼都是S O C K E T _ E R R O R。一旦返回錯誤,系統就會調用W S A G e t L a s t E r r o r獲得詳細的錯誤信息。最常見的錯誤是W S A E C O N N A B O RT E D和W S A E C O N N R E S E T。兩者均涉及到即將關閉連接這一問題—要么通過超時,要么通過通信方關閉連接。另一個常見錯誤是W S A E W O U L D B L O C K,一般出現在套接字處于非暫停模
式或異步狀態時。這個錯誤主要意味著指定函數暫不能完成。
1. send和W S A S e n d
要在已建立連接的套接字上發送數據,第一個可用的A P I函數是s e n d,其原型為:
int send(
?????SOCKET s,
?????const char FAR * buf,
?????int len,
?????int flags
????);
S O C K E T參數是已建立連接的套接字,將在這個套接字上發送數據。第二個參數b u f,則是字符緩沖區,區內包含即將發送的數據。第三個參數l e n,指定即將發送的緩沖區內的字符數。最后,f l a g s可為0、M S G _ D O N T R O U T E或M S G _ O O B。另外, f l a g s還可以是對那些標志進行按位“或運算”的一個結果。M S G _ D O N T R O U T E標志要求傳送層不要將它發出的包路
由出去。由基層的傳送決定是否實現這一請求(例如,若傳送協議不支持該選項,這一請求就會被忽略)。M S G _ O O B標志預示數據應該被帶外發送。
對返回數據而言,s e n d返回發送的字節數;若發生錯誤,就返回S O C K E T _ E R R O R。常見的錯誤是W S A E C O N N A B O RT E D,這一錯誤一般發生在虛擬回路由于超時或協議有錯而中斷的時候。發生這種情況時,應該關閉這個套接字,因為它不能再用了。遠程主機上的應用通過執行強行關閉或意外中斷操作重新設置虛擬虛路時,或遠程主機重新啟動時,發生的則是W S A E C O N N R E S E T錯誤。再次提醒大家注意,發生這一錯誤時,應該關閉這個套接字。最
后一個常見錯誤是W S A E T I M E O U T,它發生在連接由于網絡故障或遠程連接系統異常死機而引起的連接中斷時。
send API函數的Winsock 2版本是W S A S e n d,它的定義如下:
int WSASend(
???????SOCKET s,
???????LPWSABUF lpBuffers,
???????DWORD???dwBufferCount,
???????LPWORD??lpNumberOfBytesSent,
???????DWORD???dwFlags,
???????LPWSAOVERLAPPED?lpOverlapped,
???????LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE
??????);
這個套接字是一個連接會話的有效句柄。第二個參數是指向一個或多個W S A B U F結構的指針。它既可是一個獨立的結構,又可以是一組結構。第三個參數指明準備投遞的W S A B U F結構數。記住,每個W S A B U F結構本身就是一個字符緩沖和緩沖長度。為何打算同時發送多個緩沖呢?也許大家不太明白其中的原因。這就是我們稍后要講的“分散集中I / O模式”;但是,在一個已建立連接的套接字上利用多緩沖來發送數據時,順序是從第一個到最后一個W S A B U F結構。l p N u m b e r O f B y t e s S e n t是指向D W O R D(是W S A S e n d調用返回的)的指針,其中包含字節總發送數。d w F l a g s參數相當于它在s e n d中的等同物。最后兩個參數—l p O v e r l a p p e d和l p C o m p l e t i o n R O U T I N E—用于重疊I / O。重疊I / O是Wi n s o c k支持的異步I / O模式之一,
W S A S e n d函數把l p N u m b e r O f B y t e s S e n t設為寫入的字節數。成功的話,該函數就返回0,
否則就返回S O C K _ E R R O R,常見錯誤和s e n d函數的情形一樣。
2. WSASendDisconnect
該函數非常特殊,一般不用。其原型是:
int WSASendDisconnect(?
????????????SOCKET s,
????????????LPWSABUF lpOUTboundDisconnectData
???????????);
該函數起初將套接字置為關閉狀態,發送無連接的數據。當然,它只能用于支持從容關機和無連接數據的傳輸協議。目前還沒有傳輸提供者支持無連接的數據。W S A S e n d D i s c o n n e c t函數的行為和利用S D _ S E N D參數調用s h u t d o w n 函數差不多,但它另外還要發送包含在b o u n d D i s c o n n e c t D a t a參數中的數據。后來的數據禁止在這個套接字上發送。如果調用失敗,
W S A S e n d D i s c o n n e c t i o n就會返回S O C K E T _ E R R O R。使用該函數可能會出現s e n d函數中出現的某些錯誤。
帶外數據
對已建立連接的流套接字上的應用來說,如果需要發送的數據比流上的普通數據重要得多,便可將這些重要數據標記成“帶外數據”(Out-of-band, OOB)。位于連接另一端的應用可通過一個獨立的邏輯信道(從概念上講,該邏輯信道與數據流無關)來接收和處理O O B數據。
在T C P中,O O B數據由一個緊急1位標記(叫作U R G)和T C P分段頭中的一個1 6位的指針組成。這里的標記和指針把指定的下行流字節當作緊急數據。實現緊急數據的兩種特殊方法目前只能在T C P.RFC 793中見到,該索引對T C P進行了描述,并引入了“緊急數據”這一概念,表明T C P頭中的緊急指針是緊急數據字節之后那個字節的絕對偏移。但是在RFC 11 2 2中,卻將緊急偏移描述成指向緊急字節本身。
Wi n s o c k規格中,與協議無關的O O B數據和T C P的O O B數據實施(緊急數據)均采用了O O B這一術語。要查看待發數據中是否包含緊急數據,必須通過S I O C AT M A R K選項調用i o c t l s o c k e t函數。第9章將介紹S I O C AT M A R K的用法。
Wi n s o c k提供了獲得緊急數據的幾個方法。一是緊急數據一旦在線插入,它就會出現在普通數據流中;二是可以關閉在線插入,這樣,不連續調用接收函數就會只返回緊急數據。至于控制O O B數據行為的套接字選項S O _ O O B I N L I N E,我們也將在第9章詳細討論。
Te l n e t和R l o g i n使用緊急數據是有原因的。盡管如此,除非你計劃編寫自己的Te l n e t和R l o g i n,否則就應該遠離緊急數據。因為它不容易定義,而且其他平臺上的實施情況可能和Wi n 3 2有所不同。在迫不得已的情況下使用緊急數據,必須發信號通知通信方為緊急數據執行
一個獨立的控制套接字,并為普通數據的傳輸保留主要的套接字連接。