BSD Socket 簡易入門手冊(轉)
介紹
類比 (什麼是 socket ?)
裝上你的新電話(怎樣偵聽?)
撥號 (如何呼叫 socket)
談話(如何透過 sockets 交談)
掛起(結束)
世界語(交流的語言很重要)
未來在你的掌握了(下一步?)
介紹
當你進入 UNIX 的神秘世界後,立刻會發現越來越多的東西難以理解。對於大多數人來說,BSD socket
的概念就是其中一個。這是一個很短的教程來解釋他們是什麼、他們如何工作並給出一些簡單的程式碼來解釋如何使
用他們。
類比 (什麼是 socket ?)
socket 是進行程式間通訊(IPC)的 BSD 方法。這意味著 socket 用來讓一個程式和其他的程式互通訊息,就象我們
用電話來和其他的人交流一樣。
用電話來比喻是很恰當的,我們在後面將一直用電話這個概念來描敘 socket 。
裝上你的新電話(怎樣偵聽?)
一個人要能夠收到別人打給他的電話,首先他要裝上一門電話。同樣,你必須先建立 socket 以偵聽線路。這個過
程包含幾個步驟。首先,你要建立一個新的
socket,就象先裝上電話一樣。socket() 命令就完成這個工作。
因為 sockets 有幾種型別,你要註明你要建立什麼型別的。你要做一個選擇是 socket 的地址格式。如同電話有音
頻和脈衝兩種形式一樣,socket
有兩個最重要的選項是 AF_UNIX 和 IAF_INET。AF_UNIX 就象 UNIX 路徑名一樣識別 sockets。這種形式對於在同
一臺機器上的 IPC
很有用。而 AF_INET 使用象 192.9.200.10 這樣被點號隔開的四個十進位制數字的地址格式。除了機器地址以外,還
可以利用埠號來允許每臺機器上的多個
AF_INET socket。我們這裡將著重於 AF_INET 方式,因為他很有用並廣泛使用。
另外一個你必須提供的引數是 socket 的型別。兩個重要的型別是 SOCK_STREAM 和 SOCK_DGRAM。 SOCK_STREAM
表明資料象字元流一樣透過 socket 。而 SOCK_DGRAM 則表明資料將是資料包(datagrams)的形式。我們將講解
SOCK_STREAM
sockets,他很常見並易於使用。
在建立 socket 後,我們就要提供 socket 偵聽的地址了。就象你還要個電話號碼來接電話一樣。bind() 函式來處
理這件事情。
SOCK_STREAM sockets 讓連線請求形成一個佇列。如果你忙於處理一個連線,別的連線請求將一直等待到該連線處
理完畢。listen()
函式用來設定最大不被拒絕的請求數(一般為5個)。一般最好不要使用 listen() 函式。
下面的程式碼說明如何利用 socket()、 bind() 和 listen() 函式建立連線並可以接受資料。
/* code to establish a socket; originally from bzs@bu-cs.bu.edu*/int establish(unsigned short portnum){ char myname[MAXHOSTNAME+1];int s;struct sockaddr_in sa;struct hostent *hp;memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear our address */gethostname(myname, MAXHOSTNAME); /* who are we? */hp= gethostbyname(myname); /* get our address info */if (hp == NULL) /* we don't exist !? */return(-1);sa.sin_family= hp->h_addrtype; /* this is our host address */sa.sin_port= htons(portnum); /* this is our port number */if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0) /* create socket */return(-1);if (bind(s,&sa,sizeof(struct sockaddr_in)) < 0) {close(s);return(-1); /* bind address to socket */}listen(s, 3); /* max # of queued connects */return(s);}
在建立完 socket 後,你要等待對該 socket 的呼叫了。accept() 函式為此目的而來。呼叫 accept()
如同在電話鈴響後提起電話一樣。Accept() 返回一個新的連線到呼叫方的 socket 。
下面的程式碼演示使用是個演示。
/* wait for a connection to occur on a socket created with establish()*/int get_connection(int s){ int t; /* socket of connection */if ((t = accept(s,NULL,NULL)) < 0) /* accept connection if there is one */return(-1);return(t);}
和電話不同的是,在你處理先前的連線的時候,你還可以接受呼叫。為此,一般用 fork 來處理每個連線。下面的
程式碼演示如何使用 establish() 和
get_connection() 來處理多個連線。
#include
撥號 (如何呼叫 socket)
現在你應該知道如何建立 socket 來接受呼叫了。那麼如何呼叫呢?和電話一樣,你要先有個電話。用 socket()
函式來完成這件事情,就象建立偵聽的
socket 一樣。
在給 socket 地址後,你可以用 connect() 函式來連線偵聽的 socket 了。下面是一段程式碼。
int call_socket(char *hostname, unsigned short portnum){ struct sockaddr_in sa;struct hostent *hp;int a, s;if ((hp= gethostbyname(hostname)) == NULL) { /* do we know the host's */errno= ECONNREFUSED; /* address? */return(-1); /* no */}memset(&sa,0,sizeof(sa));memcpy((char *)&sa.sin_addr,hp->h_addr,hp->h_length); /* set address */sa.sin_family= hp->h_addrtype;sa.sin_port= htons((u_short)portnum);if ((s= socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) /* get socket */return(-1);if (connect(s,&sa,sizeof sa) < 0) { /* connect */close(s);return(-1);}return(s);}
這個函式返回一個可以流過資料的 socket 。
談話(如何透過 sockets 交談)
好了,你在要傳輸資料的雙方建立連線了,現在該傳輸資料了。read() 和 write() 函式來處理吧。除了在 socket
讀寫和檔案讀寫中的一個區別外,和處理一般的檔案一樣。區別是你一般不能得到你所要的數目的資料。所以你要
一直迴圈到你需要的資料的到來。一個簡單的例子:將一定的資料讀到快取。
int read_data(int s, /* connected socket */char *buf, /* pointer to the buffer */int n /* number of characters (bytes) we want */){ int bcount; /* counts bytes read */int br; /* bytes read this pass */bcount= 0;br= 0;while (bcount < n) { /* loop until full buffer */if ((br= read(s,buf,n-bcount)) > 0) {bcount += br; /* increment byte counter */buf += br; /* move buffer ptr for next read */}else if (br < 0) /* signal an error to the caller */return(-1);}return(bcount);}
相同的函式也可以寫資料,留給我們的讀者吧。
掛起(結束)
和你透過電話和某人交談後一樣,你要在 socket 間關閉連線。一般 close() 函式用來關閉每邊的 socket
連線。如果一邊的已經關閉,而另外一邊卻在向他寫資料,則返回一個錯誤程式碼。
世界語(交流的語言很重要)
現在你可以在機器間聯絡了,可是要小心你所說的話。許多機器有自己的方言,如 ASCII 和
EBCDIC。更常見的問題是位元組順序問題。除非你一直傳輸的都是文字,否則你一定要注意這個問題。幸運的是,人
們找出瞭解決的辦法。
在很久以前,人們爭論哪種順序更“正確”。現在必要時有相應的函式來轉換。其中有 htons()、ntohs()、
htonl() 和
ntohl()。在傳輸一個整型資料前,先轉換一下。
i= htonl(i);
write_data(s, &i, sizeof(i));
在讀資料後,再變回來。
read_data(s, &i, sizeof(i));
i= ntohl(i);
如果你一直堅持這個習慣,你將比別人少出錯的機會。
未來在你的掌握了(下一步?)
就用我們剛才討論的東西,你就可以寫自己的通訊程式了。和對待所有的新生事物一樣, 最好還是看看別人已經做
了些什麼。這裡有許多關於 BSD socket
的東西可以參考。
請注意,例子中沒有錯誤檢查,這在“真實”的程式中是很重要
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-941487/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- BSD socket入門(轉)
- CMake簡易入門
- gdb 簡易入門
- Redis入門手冊Redis
- Docker入門手冊Docker
- GitHub 簡易入門指南Github
- Git簡易快速入門Git
- Spring入門學習手冊 1:最簡單的反轉控制Spring
- 入門 go 隨手寫了個簡易聊天室Go
- YAML語法簡易入門YAML
- aptitude 簡明手冊(轉)APT
- Fvwm新手入門不完全手冊(原創) (轉)
- vue-router 2 簡易入門Vue
- jQuery簡明參考手冊——30分鐘快速入門jQueryjQuery
- Java GUI入門手冊-AWT篇JavaGUI
- MxDraw雲圖快速入門手冊
- Frida官方手冊 - 快速入門
- UNIX Domain Socket實現簡易聊天AI
- jmeter 效能測試入門手冊分享JMeter
- React V16入門手冊(1)React
- React V16入門手冊(2)React
- Socket.IO 入門
- CSS工具-Flexbox簡易入門教程CSSFlex
- XML輕鬆學習手冊(2)XML快速入門之二(轉)XML
- XML輕鬆學習手冊(2)XML快速入門之三(轉)XML
- pgpool-II 4.3 中文手冊 - 入門教程
- 寫給新人的React快速入門手冊React
- DZ外掛製作簡易入門教程(自學手記)第一篇
- 給萌新的Flexbox簡易入門教程Flex
- Go Web開發(Gin框架)簡易入門教程GoWeb框架
- 手寫簡易PromisePromise
- 手寫簡易webpackWeb
- 易優load載入資原始檔標籤-EyouCms手冊
- Python資料分析入門知識手冊Python
- CDH5 快速入門手冊v1.0H5
- Linux下的網路協議分析工具-tcpdump 快速入門手冊(轉)Linux協議TCP
- 簡易的伺服器介面開發入門教程伺服器
- 前端學習 node 快速入門 系列 —— 簡易版 Apache前端Apache