最近在學習socket程式設計,根據自己的學習過程及學習筆記,下面來梳理一下如何實現乙個簡單的回射客戶-伺服器模型,也藉此來熟悉一下socket、bind、listen、accept、connect這些函式的使用。
簡單的回射客戶/伺服器模型
下面先看一下乙個客戶/伺服器模型的框架圖。
可以看到,伺服器建立過程一般是:
1)建立套接字,使用socket函式,這個時候的套接字是主動套接字;
2)初始化伺服器端位址,並使用bind函式將套介面與該位址進行繫結;
3)監聽,使用listen函式,將套介面從close狀態轉為監聽狀態才能夠接收客戶端發起的連線,同時經過監聽之後,伺服器端的套接字從主動狀態(發起連線)變為被動狀態(接收連線);
4)等待接收連線,accept函式,使用該函式後,伺服器端一直處於阻塞狀態,直到客戶端的連線到達;
5)等客戶端的連線到達後,雙方開始進行通訊(讀寫資料);
客戶端建立的過程就相對簡單了:
1)建立套接字;
2)使用connect函式發起連線(過程中要經過三次握手);
3)連線成功,雙方相互進行通訊;
下面以**的方式具體說明每一步驟的實現。
伺服器端:
需要對上述的一些步驟做一些說明:// 1. 建立套接字
int listenfd;
if((listenfd = socket(af_inet, sock_stream, 0)) < 0)
perror("socket create error");
// 2. 初始化位址
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = af_inet;//位址族
servaddr.sin_port = htons(5188); //埠
servaddr.sin_addr.s_addr = htonl(inaddr_any);// 表示本機的任意位址,當然也可以自己指定
= inet_addr("127.0.0.1");
// 3. 繫結bind
if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
perror("bind error");
// 4. 監聽listen
if(listen(listenfd, somaxconn) < 0)//第二個引數表示每乙個埠的最大監聽佇列長度
perror("listen error");
// 5. 接收連線
// 在接收連線前,先定義乙個位址結構,用來儲存對等方的位址
struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(peeraddr);
memset(&peeraddr, 0, peerlen);
int conn;
// 成功返回對等方的套介面
if((conn = accept(lisenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0)
perror("accept error");
//輸出客戶端的位址和埠(僅測試用)
printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
// 至此,雙方連線已完成,可以進行通訊
char recvbuf[1024];
while(1)
//關閉套介面
close(lisenfd);
close(conn);
1)在初始化位址的時候,伺服器端位址可以指定為具體某一ip,也可以是inaddr_any。這裡建議選用inaddr_any引數,表示位址0.0.0.0,也就是不確定的位址,或「所有位址」、「任意位址」。如果你的伺服器有多個網絡卡,你要在5188這個埠上監聽,所有傳送到伺服器的這個埠,不管是哪個網絡卡/哪個ip位址接收到的資料,都可以進行處理。
2)關於listen函式中的第二個引數。每乙個處於監聽狀態的埠,都要自己的監聽佇列,那麼該引數就指定了監聽佇列的長度。我們可以自己指定乙個正整數,也可以使用引數somanconn,它表示每個埠的最大監聽佇列長度。
客戶端:
// 1. 建立套接字
int sock;
if((sock = socket(af_inet, sock_stream, 0)) < 0)
perror("socket create error");
// 2. 初始化乙個你要連線的對方的位址
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr);
servaddr.sin_family = af_inet;
servaddr.sin_port = htons(5188);
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
// 3. 發起連線
if(connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
perror("connect error");
// 4. 進行通訊(讀寫資料)
char recvbuf[1024] = ;
char sendbuf[1024] = ;
while(fgets(sendbuf, sizeof(sendbuf), stdin) != null)
//關閉套介面
close(sock);
用select改進回射客戶 伺服器模型
這一節主要來說一下如何用select函式來改進我們前面的客戶端 伺服器模型。前面我們在處理多客戶端模型時,每當連線乙個客戶端時,伺服器端就需要開闢乙個新的程序來處理新的客戶端,這樣就會耗費很大的記憶體資源。而select函式允許程序指示核心等待多個事件中的任何乙個發生,並只有在有乙個或多個事件事件發...
TCP 回射伺服器
tcp reflect server client tcp回射伺服器。學習了 unp 的第五章前面的知識,自己把 敲出來了,加深了理解吧。簡單地說就是,client傳送給server一條訊息 一行文字 server再將同樣地訊息傳送回client。就像這樣 用到的函式和api包括 1 socket ...
Linux C 回射伺服器
回射伺服器就是服務端將客戶端的資料傳送回去。我實現的回射伺服器返回增加了時間。服務端 可以很容易看懂 cpp view plain copy include include include include include include include include include define ...