天天看點

基于TCP的伺服器端和用戶端

在之前我們已經學過了如何建立套接字和配置設定位址端口,接下來我們主要說說如何收發資料,這一篇主要講面向連接配接的傳輸方式。

1、了解TCP/UDP

TCP是Transmission Control Protocol(傳輸控制協定)的簡寫,意為“對資料傳輸過程的控制”

基于TCP的伺服器端和用戶端

可以看出,TCP/IP協定棧又分為四層,分層可以将大問題化解成小問題

;當然更重要的原因是,通過标準化設計開放式系統,在技術日益發展的今天,所有人遵循一種标準,才能持久發展。程式設計中面向對象的方法也是标準化思想的展現。

鍊路層負責硬體标準,ip層負責路徑選擇,但不保證資料可靠傳輸。TCP對于丢失的資料會重傳,确認機制保證了資料傳輸的可靠性。

上面這些都是套接字内部自動實作的,網絡程式設計的大部分内容就是設計應用層協定。

2、實作基于TCP的伺服器端/用戶端

TCP伺服器端的預設函數調用順序

基于TCP的伺服器端和用戶端

調用socket函數建立套接字,聲明并初始化位址資訊結構體變量,調用bind函數向套接字配置設定位址。這兩個過程之前讨論過,下面講一下之後的過程。

(3)進入等待連接配接請求狀态

我們已調用bind函數給套接字配置設定了位址,接下來就要通過調用listen函數進入等待連接配接請求狀态。隻有調用了listen函數,用戶端才能進入可發出連接配接請求的狀态(用戶端才能調用connect函數,不然會發生錯誤)。

#include <sys/socket.h>
int listen(int sock, int backlog);
/*
 * 成功時傳回0。,失敗時傳回-1
 * sock 希望進入等待連接配接請求狀态的套接字檔案描述符,傳遞的描述符套接字參數稱為伺服器端套接字(監聽套接字)
 * backlog 連接配接請求等待隊列(Queue)的長度
 */
           

用戶端連接配接請求本身也是從網絡中接收到的一種資料,而要想接收就需要套接字。此任務就由伺服器端套接字完成,即第一個參數。

(4)受理用戶端連接配接請求

調用listen函數後,若有新的連接配接請求,則應按序受理。受理請求意味着進入可接收資料的狀态。那麼我們又需要用到套接字了!大家可能認為可以使用伺服器端套接字,但伺服器端套接字是做門衛的。如果在與用戶端的資料交換中使用門衛,那就沒辦法受理下一個連接配接請求并領到等候室去了。是以需要另一個套接字,但沒有必要親自建立。下面函數将自動建立套接字,并連接配接到發起請求的用戶端。

#include <sys/socket.h>
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
/*
 * 成功時傳回建立的套接字檔案描述符,失敗時傳回-1
 * sock 伺服器套接字的檔案描述符
 * addr 儲存發起連接配接請求的用戶端位址資訊的變量位址值,調用函數後向傳遞來的位址變量參數填充用戶端位址資訊
 * 

           

accept函數受理連接配接請求等待隊列中待處理的用戶端連接配接請求。函數調用成功時,accept函數内部将産生用于資料I/O的套接字,并傳回其檔案描述符。套接字是自動建立的,并自動與發起連接配接請求的用戶端建立連接配接。

3、TCP用戶端的預設函數調用順序

建立套接字和請求連接配接就是用戶端的全部内容。與伺服器端相比,差別就在于“請求連接配接“,它是建立用戶端套接字後向伺服器端發起的連接配接請求。伺服器端調用listen函數後建立連接配接請求等待隊列,之後用戶端即可請求連接配接。

#include <sys/socket.h>
int connect(int sock, struct sockaddr *servaddr, socklen_t addrlen);
/*
 * 成功時傳回0,失敗時傳回-1
 * sock 用戶端套接字檔案描述符
 * servaddr 儲存目标伺服器端位址資訊的變量位址值
 * addrlen 以位元組為機關傳遞給第二個結構體參數servaddr的位址變量長度
 */
           

用戶端調用connect函數後,發生一下情況之一才會傳回(完成函數調用)。

伺服器端接收連接配接請求。

發生斷網等異常情況而終端連接配接請求。

需要注意,所謂”接收連接配接“并不意味着伺服器端調用accept函數,其實是伺服器端把連接配接請求資訊記錄到等待隊列。是以connect函數傳回後并不立即進行資料交換。

用戶端套接字位址資訊在哪?

何時? 調用connect函數時。

何地? 作業系統,準确地說實在核心中。

如何? IP用計算機的IP,端口随機。

用戶端的IP位址和端口在調用connect函數時自動配置設定,無需調用标記的bind函數進行配置設定。

4、基于TCP的伺服器端/用戶端函數調用關系

基于TCP的伺服器端和用戶端

5、實作疊代伺服器端/用戶端

之前我們讀取一個資料後就退出服務了,我們可以服務一次後關閉這個用戶端的套接字,但是伺服器端套接字還在,還可以循環調用accept函數,然後接受其他用戶端的請求,每次又把伺服器端接受的資料傳輸給用戶端。

伺服器端在同一時刻隻與一個用戶端相連,并提供回身服務。

伺服器端依次向5個用戶端提供服務并退出。

用戶端接收使用者輸入的字元串并發送到伺服器端。

伺服器端将接收的字元串資料傳回用戶端

伺服器端與用戶端之間的字元串回聲一直執行到用戶端輸入Q為止。

在這裡可能會面臨資料一次傳輸不完,寫多次讀一次的情況,這不是我們希望看到的結果,因為面向連接配接的TCP是沒有資料邊界的,如何解決?在下面一篇會給出答案。

繼續閱讀