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;
}
基於TCP UDP的socket程式設計
基於tcp 面向連線 的socket程式設計 伺服器端順序 1.建立套接字 socket 2.將套接字繫結到乙個本地位址和埠上 bind 3.將套接字設為監聽模式,準備接收客戶請求 listen 4.等待客戶請求的到來 當請求帶來後,接受連線請求,返回乙個新的對應於此次連線的套接字 accept 5...
基於TCP UDP的socket程式設計
基於tcp 面向連線 的socket程式設計 伺服器端順序 1.建立套接字 socket 2.將套接字繫結到乙個本地位址和埠上 bind 3.將套接字設為監聽模式,準備接收客戶請求 listen 4.等待客戶請求的到來 當請求帶來後,接受連線請求,返回乙個新的對應於此次連線的套接字 accept 5...
socket程式設計(1)簡單的TCP UDP程式設計
socket程式設計是一種與底層網路協議無關的程式設計方式,socket意味一種插口,即乙個位址配上乙個埠就構成了一端插口,既然他與底層協議無關,所以我們在使用socket 程式設計的時候,就可以任意選用哪種網路協議,如最流行的tcp ip協議。在所有socket程式設計前腰包含標頭檔案 下面是基於...