网络编程套接字(一)
網絡編程套接字(一)
文章目錄
- 網絡編程套接字(一)
- 一、基礎知識
- 二、sock編程接口
一、基礎知識
-
1. 理解源IP地址和目的IP地址
-
在IP數據包頭部中,有兩個IP地址,分別叫源IP地址和目的IP地址。這兩個很好理解,見名知義。
-
思考: 我們光有IP地址就可以完成通信了嘛? 想象一下發qq消息的例子, 有了IP地址能夠把消息發送到對方的機器上,但是還需要有一個其他的標識來區分出, 這個數據要給哪個程序進行解析。
-
2. 認識端口號
-
端口號是傳輸層協議內容 :
a. 端口號是一個2字節的16為整數
b.端口號是用來標識一個進程,告訴操作系統,當前這個數據要交給那個進程去處理
c.IP地址 + 端口號 能夠唯一標識網絡上的某一臺主機的某一個進程
d.一個端口號只能被一個進程占用 -
3. 理解端口號和進程ID
-
一個進程可以綁定多個端口號,但是一個端口號只能被一個進程綁定
-
一個網絡應用程序對應一個端口
-
一個端口對應一至多個進程;
-
一個進程對應一至多個線程
-
4. 理解源端口號和目的端口號
-
在傳輸層協議(TCP/UDP)的數據段中有兩個端口號,分別叫源端口號和目的端口號
-
源端口就是指本地端口,源端口就是本機程序用來發送數據的端口。
-
目的端口就是遠程端口,目的端口就是對方主機用哪個端口接收
-
5. 初識TCP協議
-
傳輸層協議
-
有鏈接(相當于打電話)
-
可靠傳輸(這里的可靠只是相對而言,“可靠“具體是指發送/接收數據的成功與否自己知道,并不是100%傳輸成功)
-
面向字節流
-
6. 初識UDP協議
-
傳輸層協議
-
無連接(如消息,短信)
-
不可靠傳輸(“不可靠“具體是指發送/接收數據的成功與否自己不知道,并不是說傳輸數據一定是不可靠的)
-
面向數據報
-
7. 網絡字節序(大端序)
-
我們已經知道,內存中的多字節數據相對于內存地址有大端和小端之分,
磁盤文件中的多字節數據相對于文件中的偏移地址也有大端小端之分, 網絡數據流同樣有大端小端之分. 那么如何定義網絡數據流的地址呢? -
發送主機通常將發送緩存區中的數據按照內存地址從低到高的順序發出
-
接收主機通常把從網絡上接收到的字節依次保存在接受緩存區中,也就是按內存地址從低到高的順序保存的
-
因此,網絡數據流的地址應該這樣規定:先發出的數據是低地址,后發出的數據是高地址
-
TCP/IP協議規定,網絡數據采用 大端字節序,即先低地址后高地址
-
不論主機是大端機還是小端機,都會按造這個TCP/IP規定的網絡字節序來發送/接受數據
-
如果當前發送主機是小端機,就需要先將數據轉為大端;否則直接忽略這一步
-
8.網絡字節序和主機字節序的轉換
-
目的:為使網絡程序具有可移植性,使同樣的C代碼在大端和小端計算機上編譯后都能正常運行,可以調用以下庫函數做網絡字節序和主機字節序的轉換
- h代編host(主機),n代表網絡(network),l代表32位長整數,s表示16位短整數
- 例如htonl表示將32位的長整數從主機字節序轉換為網絡字節序,例如將IP地址轉換后準備發送
- 如果主機是小端字節序,這些函數將參數做相應的大小端轉換然后返回;
- 如果主機是大端字節序,這些 函數不做轉換,將參數原封不動地返回
二、sock編程接口
- 1.socket函數—>創建socket
- 作用:創建一個socket文件描述符(相當于整個socket編程的操作句柄),也就是文件描述符表的下表,根據前面所說,可以用一個端口號關聯一個進程,在這里就是拿端口號和一個socket綁定在一起
- 參數:
| domain | domain 為地址族(Address Family),也就是 IP 地址類型,常用的有 AF_INET 和 AF_INET6。AF_INET 表示 IPv4 地址,例如 127.0.0.1;AF_INET6 表示 IPv6 地址,例如 1030::C9B4:FF12:48AA:1A2B。 |
| type | type 為數據傳輸方式/套接字類型,常用的有 SOCK_STREAM(流格式套接字/面向連接的套接字) 和 SOCK_DGRAM(數據報套接字/無連接的套接字) |
| protocol | protocol 表示傳輸協議,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分別表示 TCP 傳輸協議和 UDP 傳輸協議。如果操作系統可以根據前面兩個參數成功推演出協議類型,那么此處可以直接為0 |
-
有了地址類型和數據傳輸方式,還不足以決定采用哪種協議嗎?為什么還需要第三個參數呢?
-
正如大家所想,一般情況下有了 domain 和 type 兩個參數就可以創建套接字了,操作系統會自動推演出協議類型
-
除非遇到這樣的情況:有兩種不同的協議支持同一種地址類型和數據傳輸類型。如果我們不指明使用哪種協議,操作系統是沒辦法自動推演的。
-
例如
-
如果使用 SOCK_STREAM 傳輸數據,那么滿足這兩個條件的協議只有 TCP,因此可以這樣來調用 socket() 函數:
- 這種套接字稱為 TCP 套接字。
- 如果使用 SOCK_DGRAM 傳輸方式,那么滿足這兩個條件的協議只有 UDP,因此可以這樣來調用 socket() 函數:
- 這種套接字稱為 UDP 套接字。
- 上面兩種情況都只有一種協議滿足條件,可以將 protocol 的值設為 0,系統會自動推演出應該使用什么協議,如下所示:
- 2.bind函數—>綁定端口信息
- 功能:bind為套接字sockfd指定本地地址my_addr
- 參數
| sockfd | socket創建出的套接字,也就是文件描述符 |
| my_addr | 該參數是一個指向結構sockaddr的指針,sockaddr封裝了地址的類型、IP地址、端口號,用的時候需要把這些成員變量附上值,也就是綁定的過程,綁定本地主機的IP端口號信息 |
| addrlen | 這個參數是第二個參數的大小,直接sizeof即可 |
- 3.listen函數—>開始監聽
- 功能:調用listen使其能夠自動接收到來的連接并且為連接隊列指定一個長度限制.
- listen調用僅適用于 SOCK_STREAM 或者SOCK_SEQPACKET 類型的套接字(因為前面已經創建號套接字和綁定好端口號相關信息,但是別人是無法訪問到我的
- 通過listen就可以和我鏈接到,但是處于鏈接隊列的所有請求都是處于傾聽狀態)
- 參數:
| s | socket套接字 |
| backlog | 指定完成連接隊列的最大長度.如果一個連接請求到達時未完成連接隊列已滿,那么客戶端將接收到錯誤 |
- 4.accept函數—>接受請求
- 功能:它從未完成連接隊列中取出第一個連接請求,創建一個和參數s屬性相同的連接套接字,并為這個套接字分配一個文件描述符,然后以這個描述符返回.新創建的描述符不再處于傾聽狀態,原套接字s不受此調用的影響.
- 注意任意一個文件描述符標志(任何可以被fcntl以參數F_SETFL設置的值,比如非阻塞式或者異步狀態)不會被 accept.
- 參數
| s | 套接字 |
| addr | 是一個指向結構sockaddr的指針,是輸出型參數,這個結構體以連接實體地址填充. |
| addrlen | 是一個實時參數: 它的大小應該能夠足以容納參數 addr所指向的結構體;在函數返回時此參數將以字節數表示出返回地址的 實際長度.若 addr 使用NULL作為參數,addrlen將也被置為NULL |
- 5.connect函數—>建立鏈接
- 功能:connect()系統調用將文件描述符sockfd引用的套接字連接到addr指定的地址
- 參數
| sockfd | 套接字 |
| addr | 該參數是一個指向結構sockaddr的指針,sockaddr封裝了地址的類型、IP地址、端口號,用的時候需要把這些成員變量附上值 |
| addrlen | sizeof(addr) |
- 6.recv函數
- 功能:接收遠端主機傳來的數據,并把數據存到由參數buf 指向的內存空間
- 參數
| sockfd | sockfd為前面accept的返回值.即new_fd,也就是新的套接字 |
| buf | 存儲接收到的數據的緩沖區 |
| 一般為0 |
- 7.recvfrom函數
- 參數
| src_addr | 輸出型參數,數據發送者地址,函數調用后該地址結構被填充 |
| addrlen | sizeof(src_addr) |
- 8.send函數
- 功能:發送數據給指定的遠端主機
- 參數
| s | s為前面accept的返回值.即new_fd |
| msg | msg一般為常量字符串,也就是服務器返回給客戶端的內容 |
| len | 發送數據的長度 |
| flags | 通常為0 |
- 9.sendto函數
- 參數
| to | 指向接收數據的主機地址信息的結構體(sockaddr_in需類型轉換) |
| tolen | sizeof(to) |
總結
以上是生活随笔為你收集整理的网络编程套接字(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络基础(一)
- 下一篇: 求1+2+3+...+n,要求不能使用乘