再學BSD Socket


最近要做ios的socket.看了看ios所有類似點對點通信的文檔.bsd socket,cfsocket,cfnetwork,cfstream

今天寫總結下bsd socket.由於以前做c++的時候,用過.

常用函數:

server:

socket(),bind(),listen(),accept(),read(),write()/recv(),send().

client:

socket(),connect(),read(),write()/recv(),send().


需要死循環的函數:

server:

accept(),read()/recv()

client:

read()/recv()


read write 區別 send recv

原文地址

 1)connect()+write()+read() [適用於TCP] 這是一個“古老”的I/O搭配了,“遠在”無名管道的工作部分就已經有詳細地記錄了,不過在這裏偶還是要 講一下。write()+read()主要出現在管道I/O工作上,無論是有名管道還是無名管道,它們主要都是依靠writ e()+read()進行基本的數據通信的,這個搭配屬於UNIX系統中非常低層的I/O系統調用了,而TCP開始設計時 就被當作是網絡上傳輸管道數據的替代品,當然也就順理成章地繼承這個基本的I/O調用搭配了。
下面講解的 write()+read()調用主要是以BSD Socket下的運用方式爲主
 必須頭: #include <sys/types.h> #include <sys/uio.h> #include <unistd.h> 
關於write() ssize_t write(int d,const void *buf,size_t nbytes); 調用成功返回成功寫入的字節數,調用失敗則返回-1。參數1爲對象的句柄;參數2是寫入的內容;參數3是前 者的大小。 
關於read() ssize_t read(int d,void *buf,size_t nbytes); 正常調用返回成功讀入的字節數,當讀到句柄對象的底部時返回0,調用失敗返回-1。參數1爲對象句柄;參 數2是讀入容器的地址;參數3是前者的大小。

2)sendto()+recvfrom() [適用於TCP、UDP,多數用於UDP] 這是一個比較“遊動”的I/O方式調用,僅適用於UDP傳輸(也是UDP的I/O調用的魅力所在),因爲UDP本身的 特性(不需要三次握手),所以它需要一種非常靈活的傳輸模式,有了這個模式,服務端與客戶端的模式就 沒有一個很籠統的分化了(在範例中我們可以看出服務端與客戶端在程序的編排上幾乎是一致的,除了服務 端多了一個bind()調用與一個循環結構以外),程序設計者可以按照需求更巧妙地設計自己的程序。
 必須頭: #include <sys/types.h> #include <sys/socket.h> 
關於sendto() ssize_t sendto(int s,const void *msg,size_t len,int flags,const struct sockaddr *to,socklen_t tolen); 調用成功返回成功寫入的字節數,調用失敗則返回-1。參數1是套接字句柄;參數2是需要發送的數據;參數3 是前者的大小;參數4是特殊傳輸標識,其值多爲0;參數5是發送目的地的sockaddr結構主機地址的指針值; 參數6是前者的長度。 
關於recvfrom() ssize_t recvfrom(int s,void *buf,size_t len,int flags,struct sockaddr *from,socklen_t *fromlen ); 正常調用返回成功讀入的字節數,調用失敗返回-1。參數1是套接字句柄;參數2是成功接收到遠程傳輸過來 後的數據時放入的變量地址;參數3是前者的大小;參數4是特殊傳輸標識,其值多爲0;參數5是接收到的數 據的發送端的sockaddr結構主機地址的指針值;參數6是前者長度的地址值。 
/* 以前總以爲sendto()+recvfrom()調用只能用於UDP傳輸,原來這個論點是錯的,這裏偶做了個小實驗...服務 端用我在《BSD Socket在傳輸層中的應用範例(TCP)》一文中的服務端,而客戶端是: #include<sys/socket.h> #include<sys/types.h> #include<netinet/in.h> int main(int argc,char *argv[]){ int sock; struct sockaddr_in addr; char msg[101]; bzero((char *)msg,101); if((sock=socket(AF_INET,SOCK_STREAM,0))==-1){ //這裏用的是TCP printf("fail for socket./n"); exit(-1); } bzero((char *)&addr,sizeof(addr)); addr.sin_family=AF_INET; addr.sin_addr.s_addr=inet_addr(argv[1]); addr.sin_port=htons(atoi(argv[2])); printf("message:"); scanf("%100s",msg); if(sendto(sock,msg,sizeof(msg),0,(struct sockaddr *)&addr,sizeof(addr))){ //I/O這裏我用了sendto()來代替send() printf("send is ok./n"); close(sock); exit(0); }else{ printf("send is fail./n"); close(sock); exit(-1); } } 上面我用了sendto()來代替send(),並去除開始時的connect()調用(根據UDP的調用模式),結果發現必須 運行兩次服務端才能接收msg的數據,可見第一次sendto()代替connect()了,這樣才能正常地運作。但如果 在前面一開始就調用connect()的話sendto()是可以完全代替send()的,不過因爲sendto()多了兩個參數,所 以相信還不會有人會這樣調用的,這樣的使用方法僅僅用於實驗用途。 */

3)connect()+send()+recv() [適用於TCP、UDP,多數用於TCP] 因爲connect()調用在前一篇文中已經介紹過了,所以我就不多說了,下面主要談談send()+recv()。在TCP的 I/O傳輸中它們可以完全地取代write()+read()(而且在功能上回更優勝一些,看它的最後一個調用參數就知 道了);在UDP則不能完全取代sendto()+recvfrom(),原因顯而易見,因爲send()+recv()少了“遊動”地址 部分,所以如果在UDP中調用它們的話套接字根本就不知道應該發到哪裏去,這也是爲什麼在UDP中要用conne ct()調用作爲綁定了,又因爲UDP不存在所謂的“三次握手”(需要發送連接請求),所以在UDP中我們可以 把“綁定”這種行爲簡單地歸結爲:bind()調用綁定本地地址,connect()調用綁定遠程地址。 
必須頭: #include <sys/types.h> #include <sys/socket.h> 
關於send() ssize_t send(int s, const void *msg, size_t len, int flags); 調用成功返回成功寫入的字節數,調用失敗則返回-1。參數1是套接字句柄;參數2是需要發送的數據;參數3 是前者的大小;參數4是特殊傳輸標識,其值多爲0。 
關於recv() ssize_t recv(int s, void *buf, size_t len, int flags); 正常調用返回成功讀入的字節數,調用失敗返回-1。參數1是套接字句柄;參數2是成功接收到遠程傳輸過來 後的數據時放入的變量地址;參數3是前者的大小;參數4是特殊傳輸標識,其值多爲0。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章