Linux C網路程式設計的一點總結
以下僅個人總結,望網友指正。
我做的是,實現客戶端與客戶端之間互相通訊,這樣也算基本搭起來了,之前也做過一個即時通訊軟體的專案,現在溫習一下,所以點到為止。
1. 網路結構的標準模型是OSI模型,由ISO國際網際網路標準化組織定義的網路分層模型。
2. ISO/OSI七層網路模型:應用層---表示層---會話層---傳輸層---網路層---資料鏈路層---網路層
3. TCP/IP四層參考模型:應用層---傳輸層----網路互聯層---主機到網路
4. ARP(地址解析協議):完成IP地址和硬體地址的對應關係。
客戶端/伺服器網路程式設計注意點
伺服器端
1. 首先建立套接字,呼叫的函式為socket(),引數使用的一般為IPv4 Internet協議,和套接字型別為流式套接字(套接字的型別有:流式套接字(SOCK_STREAM),資料報套接字(SOCK_DGRAM)(主要用於UDP連線)及原始套接字 ),流式套接字用於TCP連線,提供序列化的,可靠的,雙向連線的位元組流。
2. 在建立套接字成功以後,也就是得到了套接字的id,這時候就可以開始bind(),對套接字地址和埠進行繫結,才能進行資料的接收和傳送。
3. 繫結函式中,使用的第一個引數為套接字fd,第二個為一個套接字的地址結構,那麼相對於AF_INET的域,我們使用結構體struct sockaddr_in這個結構體
4. struct sockaddr_in{
short int sin_family; /* 地址族 */
unsigned short int sin_port;/* 埠號 */
struct in_addr sin_addr; /*IP地址 */
unsigned char sin_zero[8]; /*填充0 以保持與struct sockaddr同樣大小 */
};
struct sockaddr {
unsignedshort sa_family; /* 地址族, AF_xxx */
char sa_data[14]; /* 14 位元組的協議地址 */
};
5. 好處在於,這個結構體可以在第四個成員中填充0,使之與scokaddr結構體一樣大小,這樣就可以完成兩種結構體的型別的轉換。
6. 下一步就是將這個結構體清空,然後在裡面填充重要的網路資訊,有域,埠和ip地址,埠和ip地址需要使用函式進行轉化,比如:埠需要使用htons()將埠的位元組順序轉化為網路的位元組順序(大端儲存),因為主機的位元組順序有時候大端有時候小端,然後還有一個inet_addr()函式,使用這個函式,將例如192.168.1.1這樣的字串ip地址轉化為二進位制資料給結構體,讓繫結的時候能夠正確辨識。
7. 接下來是監聽,也就是listen(),引數為套接字的fd和設定的監聽佇列的長度。
8. 再就是開始迴圈的接收accept(),這個函式有一個特點,就是接收完了,那麼這時候會返回一個新的套接字,這個新的套接字就是客戶端連線請求是客戶端的套接字檔案描述符fd,然後舊的,也就是原來伺服器建立的那個套接字還是在不斷的監聽和接收,新的套接字就可以通過send()和recv()函式,再新的套接字基礎上進行資料的收發。
9. 在accept成功以後,就要在伺服器端開啟一個執行緒,這樣就可以單獨的去處理某一個客戶端的請求操作。
10. 這時候可以使用傳參的方式,把新的客戶端的套接字進行傳入給執行緒的執行單元,這樣就能讓執行緒依靠這個套接字描述符進行和該客戶端的通訊了。
11. 那麼如何通訊呢?我們使用不帶緩衝的IO操作,write和read,進行對套接字為檔案描述符的操作,反正Linux下皆為檔案。
12. 這時候出現一個問題,就是阻塞問題,阻塞是一般我們自己寫伺服器和客戶端使用的方法,因為比較好用,也比較能夠理清邏輯,但是我覺得阻塞是不合理的,不能讓執行緒停在一個地方。所以這個問題需要考慮。
13. 第二個問題就是如何實現訊號的處理,如何將組合鍵讓伺服器獲取,然後做出正確的退出等操作。
客戶端
1. 首先建立套接字
2. 然後使用套接字進行連線connect(),如果連線上了伺服器就可以開始做客戶端做的操作了。
3. 客戶端的操作可以放在一個函式中,這個函式中為迴圈的做一件事情,可以使用輪詢的方式,不斷的write和read,這樣達到了阻塞型的客戶端。
4. 阻塞問題這是問題,需要解決,但是阻塞有阻塞的壞處,不阻塞也有不阻塞的壞處。