在我們日常所見的網路應用程式中,很多都是由客戶/伺服器(c/s)模型組成的。
伺服器主要承擔著提供資源的責任,通常可以為數量較多的客戶提供服務。
今天我們主要來通過乙個最基本的回射伺服器和客戶端模型的編寫,來體會到客戶和伺服器的角色定位,以及對套接字有更深的理解。
首先要有一些準備知識,了解在linux下的網路程式設計的套接字介面。
socket函式
功能:建立乙個套接字用於程序通訊。套接字在本質上就是乙個檔案描述符。
int socket(int domain, int type, int protocol);
/*domain:指定通訊協議族 //ipv4通常為af_inet
type:指定socket型別,流式套接字sock_stream
(tcp),資料報套接字sock_dgram
(udp),原始套接字sock_raw
protocol:協議型別(如控制傳輸層、網路層或者是鏈路層)
返回值:成功返回非負整數,與檔案描述符類似,稱為套介面描述字,簡稱套接字。失敗返回-1。
*/
bind函式int bind(int sockfd, const
struct sockaddr* addr, socklen_t addrlen);
/*sockfd:socket函式返回的套接字
addr:要繫結的位址
addrlen:位址長度
返回值:成功返回0,失敗返回-1
*/
listen函式
功能:將套接字用於監聽進入的連線
int listen(int sockfd, int backlog);
/*sockfd:socket函式返回的套接字
backlog:規定核心為此套接字排隊的最大連線個數
返回值:成功返回0,失敗返回-1
*/
使用listen函式之後,套接字就會變成被動套接字,是用來等待連線的,一般用於伺服器。需要繼續呼叫accept函式。
對於給定的監聽套接字介面,核心要維護兩個佇列:
1、已由客戶發出並到達伺服器,伺服器正在等待完成相應的tcp三次握手的過程
2、已經完成連線的佇列
最大連線個數等於已完成連線佇列加上未完成連線的佇列。
accept函式
功能:從已經完成連線佇列返回第乙個連線,如果已完成連線隊列為空,則阻塞。
int accept(int sockfd, struct sockaddr* addr, socklen_t *addrlen);
/*sockfd:socket函式返回的伺服器套接字
addr:將返回對等方的套接字位址
addrlen:返回對等方的套接字位址長度
返回值:成功返回0,失敗返回-1
*/
connect函式
功能:建立乙個連線至addr所指定的套接字
int connect(int sockfd, const
struct sockaddr* addr, socklen_t addrlen);
/*sockfd:socket函式返回的未連線的套接字
addr:要連線的套接字位址
addrlen:第二個引數addr的長度
*/
了解完這些基本介面後,還需要知道的是一些套接字的位址結構,如果不了解可以點這裡。
在使用套接字位址的時候記得初始化。
下面是一段常見的套接字初始化的方式。
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = af_inet;
server.sin_port = htons(atoi(argv[2])); //argv[2]代表由命令列引數傳入的埠號
server.sin_addr.s_addr = inet_addr(argv[1]); //argv[1]代表由命令列引數傳入的ip位址
有了這些知識的準備後,我們很容易就可以編寫乙個基礎的tcp伺服器。**示例如下:
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv)
int sock = socket(af_inet, sock_stream, 0);
if(sock < 0)
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = af_inet;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);
if(bind(sock, (struct sockaddr*)&server, sizeof(server)) < 0)
if(listen(sock, 10) < 0)
struct sockaddr_in client;
socklen_t len = sizeof(client);
int client_fd;
if((client_fd = accept(sock, (struct sockaddr*)&client, &len)) < 0)
char buf[1024] = ;
while(1)
close(sock);
return
0;}
下面是客戶端的**示例:
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv)
struct sockaddr_in client;
memset(&client, 0, sizeof(client));
client.sin_family = af_inet;
client.sin_port = htons(atoi(argv[2]));
client.sin_addr.s_addr = inet_addr(argv[1]);
if(connect(sock, (struct sockaddr*)&client, sizeof(client)) < 0)
char recvbuf[1024] = ;
char sendbuf[1024] = ;
while(fgets(sendbuf, sizeof(sendbuf), stdin) != null)
close(sock);
return
0;}
這乙份示例**還有很多不完善的地方,如只能接收乙個客戶的請求,在伺服器主動斷開連線後,會進入time_wait狀態等缺點,如果有興趣,可以了解setsockopt函式。 C S模型(客戶 伺服器模型)
c s模型即客戶 client 伺服器 server 模型。1.特點 伺服器提供服務,客戶請求服務。2.客戶端和伺服器之間連線的數量對應關係 多個客戶程序可以同時訪問乙個服務程序,乙個客戶程序可以同時訪問多個伺服器程序提供的服務。3.客戶端和伺服器所在不同網路位置所適用的場合 執行在同乙個機器上的場...
客戶端 伺服器程式設計模型
客戶端和伺服器是程序,不是主機。客戶端 伺服器模型中的基本操作是事務。乙個客戶端 伺服器事務由四步組成 1.當乙個客戶端需要服務時,它向伺服器傳送乙個請求,發起乙個事務。例如,當web瀏覽器需要乙個檔案時,它就傳送乙個請求給web伺服器。2.伺服器收到請求後,解釋它,並以適當的方式操作它的資源。例如...
回射客戶 伺服器模型(1)
最近在學習socket程式設計,根據自己的學習過程及學習筆記,下面來梳理一下如何實現乙個簡單的回射客戶 伺服器模型,也藉此來熟悉一下socket bind listen accept connect這些函式的使用。簡單的回射客戶 伺服器模型 下面先看一下乙個客戶 伺服器模型的框架圖。可以看到,伺服器...