linux下的socket程式設計大體上包括tcp socket、udp socket即raw socket這三種,其中tcp和udp方式的socket程式設計用於編寫應用層的socket程式,是我們用得比較多的,而raw socket則用得相對較少,不在本文介紹範圍之列。
tcp socket
基於tcp協議的客戶端/伺服器程式的一般流程一般如下:
它基本上可以分為三個部分:
一、建立連線:
伺服器呼叫
socket()
、bind()
、listen()
完成初始化後,呼叫
accept()
阻塞等待,處於監聽埠的狀態
客戶端呼叫socket()初始化後,呼叫connect()發出syn段並阻塞等待伺服器應答
伺服器應答乙個
syn-ack
段,客戶端收到後從
connect()
返回,同時應答乙個
ack段,伺服器收到後從
accept()
返回。
二、傳輸資料:
建立連線後,tcp協議提供全雙工的通訊管道,伺服器端和客戶端根據協議可以通過read和write的反覆呼叫實現資料的傳輸
三、關閉連線:
當資料傳輸已經完成後,伺服器和客戶端可以呼叫close關閉連線,一端關閉連線後,另一端read函式則會返回0,可以根據這個特徵來感應另一端的退出。
下面就以乙個簡單的echoserver演示一下如何建立伺服器端和客戶端**,其中和socket相關api都會高亮顯示。
伺服器端示例:
#include
#include
#include
#include
#include
#include
#include
#definemaxline 80
#defineserv_port 8000
intmain(void)
;servaddr.sin_family = af_inet;
servaddr.sin_addr.s_addr = htonl(inaddr_any);
servaddr.sin_port = htons(serv_port);
bind(listenfd, (sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, 20);
printf("accepting connections ...\n");
while(1)
;socklen_t cliaddr_len = sizeof(cliaddr);
intconnfd =
accept(listenfd, (sockaddr *)&cliaddr, &cliaddr_len);
charstr[inet_addrstrlen];
printf("connected from %s at port %d\n",
inet_ntop(af_inet, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));
while(true)
close(connfd);
printf("closed from %s at port %d\n",
inet_ntop(af_inet, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));}}
ps:這裡需要注意的一下的是sock函式的第二個引數sock_stream,它表示是乙個tcp連線,後面我們會介紹通過傳入sock_dgram開啟udp連線。
伺服器端主體流程就是乙個死迴圈,它接受乙個socket連線,然後將其原封不動的返回給客戶端,待客戶端退出後,關閉socket連線,再次接受下乙個socket連線。
客戶端**如下:
#include
#include
#include
#include
#include
#include
#definemaxline 80
#defineserv_port 8000
#definemessage "hello world"
intmain(intargc, char*argv)
;servaddr.sin_family = af_inet;
inet_pton(af_inet, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(serv_port);
if(0 !=
connect(sockfd, (sockaddr *)&servaddr, sizeof(servaddr)))
write(sockfd, message, sizeof(message));
intcount =
read(sockfd, buf, maxline);
printf("response from server: %s\n",buf);
close(sockfd);
return0;}
客戶端**比較簡單,這裡就不多介紹了。
udp socket
典型的udp客戶端/伺服器通訊過程如下圖所示:
由於udp不需要維護連線,程式邏輯簡單了很多,但是udp協議是不可靠的,實際上有很多保證通訊可靠性的機制需要在應用層實現,可能反而會需要更多**。
典型的示例如下:
/* server.cpp */
#include
#include
#include
#include
#definemaxline 80
#defineserv_port 8000
intmain(void)
;servaddr.sin_family = af_inet;
servaddr.sin_addr.s_addr = htonl(inaddr_any);
servaddr.sin_port = htons(serv_port);
bind
(sockfd, (sockaddr *)&servaddr, sizeof(servaddr));
printf("accepting connections ...\n");
while(1)
printf("received from %s at port %d\n",
inet_ntop(af_inet, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));
sendto
(sockfd, buf, count, 0, (sockaddr *)&cliaddr, sizeof(cliaddr));}}
/* client.cpp */
#include
#include
#include
#include
#include
#definemaxline 80
#defineserv_port 8000
intmain(intargc, char*argv)
;servaddr.sin_family = af_inet;
inet_pton(af_inet, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(serv_port);
while(fgets(buf, maxline, stdin) != null)
count =
recvfrom
(sockfd, buf, maxline, 0, null, 0);
if(count == -1)
write(stdout_fileno, buf, count);
}close(sockfd);
return0;}
Linux基礎 socket程式設計詳解
在講socket程式設計之前,先來回顧一下tcp的三握手與四揮手過程,這樣就更易理解socket程式設計了。1.tcp三握手建立連線過程 2.tcp四揮手釋放連線過程 先來張圖,看看其過程如何 針對上圖出現的函式或其它重要的函式,我在此解釋下 1.socket 申請了乙個描述符 本地可見 但不能對外...
socket程式設計基礎
對於socket在這裡我不想究其歷史,我只想說其時它是一種程序通訊的方式,簡言之就是呼叫這個網路庫的一些api函式就能實現分布在不同主機的相關程序之間的資料交換.socket中首先我們要理解如下幾個定義概念 二是埠號 用來標識本地通訊程序,方便os提交資料.就是說程序指定了對方程序的網路ip,但這個...
socket程式設計基礎
對於socket在這裡我不想究其歷史,我只想說其時它是一種程序通訊的方式,簡言之就是呼叫這個網路庫的一些api函式就能實現分布在不同主機的相關程序之間的資料交換.socket中首先我們要理解如下幾個定義概念 二是埠號 用來標識本地通訊程序,方便os提交資料.就是說程序指定了對方程序的網路ip,但這個...