一、引言
udp是tcp/ip協議中的傳輸層協議的一種,本文介紹了在linux下編寫基於udp協議的client/server模型的程式的方法,並給出了乙個echo client/server例子程式。
二、udp協議簡介
udp是一種簡單的傳輸層協議,在rfc768中有詳細描述。udp協議是一種非連線的、不可靠的資料報文協議,完全不同於提供面向連線的、可靠的位元組流 的tcp協議。雖然udp有很多不足,但是還是有很多網路程式使用它,例如dns(網域名稱解析服務)、nfs(網路檔案系統)、snmp(簡單網路管理協 議)等。
通常,udp client程式不和server程式建立連線,而是直接使用sendto()來傳送資料。同樣,udp server程式不需要允許client程式的連線,而是直接使用recvfrom()來等待直到接收到client程式傳送來的資料。
這裡,我們使用乙個簡單的echo client/server程式來介紹在linux下編寫udp程式的方法。client程式從stdin讀取資料並通過網路傳送到server程 序,server程式在收到資料後直接再傳送回client程式,client程式收到server發回的資料後再從stdout輸出。
三、udp server程式
1、編寫udp server程式的步驟
(1)使用socket()來建立乙個udp socket,第二個引數為sock_dgram。
(2)初始化sockaddr_in結構的變數,並賦值。sockaddr_in結構定義:
struct sockaddr_in ;
這裡使用「08」作為服務程式的埠,使用「inaddr_any」作為繫結的ip位址即任何主機上的位址。
(3)使用bind()把上面的socket和定義的ip位址和埠繫結。這裡檢查bind()是否執行成功,如果有錯誤就退出。這樣可以防止服務程式重複執行的問題。
(4)進入無限迴圈程式,使用recvfrom()進入等待狀態,直到接收到客戶程式傳送的資料,就處理收到的資料,並向客戶程式傳送反饋。這裡是直接把收到的資料發回給客戶程式。
//////
2、udpserv.c程式內容:
#include
#include
#include
#include
#include
#include
#define maxline 80
#define serv_port 8888
void do_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)
}///
int main(void)
do_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
return 0;}
//////四、udp client程式
1、編寫udp client程式的步驟
(1)初始化sockaddr_in結構的變數,並賦值。這裡使用「8888」作為連線的服務程式的埠,從命令列引數讀取ip位址,並且判斷ip位址是否符合要求。
(2)使用socket()來建立乙個udp socket,第二個引數為sock_dgram。
(3)使用connect()來建立與服務程式的連線。與tcp協議不同,udp的connect()並沒有與服務程式三次握手。上面我們說了udp是非 連線的,實際上也可以是連線的。使用連線的udp,kernel可以直接返回錯誤資訊給使用者程式,從而避免由於沒有接收到資料而導致呼叫 recvfrom()一直等待下去,看上去好像客戶程式沒有反應一樣。
(4)向服務程式傳送資料,因為使用連線的udp,所以使用write()來替代sendto()。這裡的資料直接從標準輸入讀取使用者輸入。
(5)接收服務程式發回的資料,同樣使用read()來替代recvfrom()。
(6)處理接收到的資料,這裡是直接輸出到標準輸出上。
2、udpclient.c程式內容:
#include
#include
#include
#include
#include
#include
#include
#include
#define maxline 80
#define serv_port 8888
///void do_cli(file *fp, int sockfd, struct sockaddr *pservaddr,
socklen_t servlen)
while(fgets(sendline, 80, fp) != null)
recvline[n] = 0; /* terminate string */
fputs(recvline, stdout);}}
/int main(int argc, char **argv)
/* init servaddr */
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = af_inet;
servaddr.sin_port = htons(8888);
if(inet_pton(af_inet, argv[1], &servaddr.sin_addr) <= 0)
sockfd = socket(af_inet, sock_dgram, 0);
do_cli(stdin, sockfd, (struct sockaddr *)&servaddr,
sizeof(servaddr));
return 0;}
//////五、執行例子程式
1、編譯例子程式
使用如下命令來編譯例子程式:
gcc -wall -o udpserv udpserv.c
gcc -wall -o udpclient udpclient.c
編譯完成生成了udpserv和udpclient兩個可執行程式。
2、執行udp server程式
執行./udpserv &命令來啟動服務程式。我們可以使用netstat
-ln命令來觀察服務程式繫結的ip位址和埠,部分輸出資訊如下:
active internet connections (only servers)
proto recv-q send-q local address foreign address state
tcp 0 0 0.0.0.0:32768 0.0.0.0:* listen
tcp 0 0 0.0.0.0:111 0.0.0.0:* listen
tcp 0 0 0.0.0.0:6000 0.0.0.0:* listen
tcp 0 0 127.0.0.1:631 0.0.0.0:* listen
udp 0 0 0.0.0.0:32768 0.0.0.0:*
udp 0 0 0.0.0.0:8888 0.0.0.0:*
udp 0 0 0.0.0.0:111 0.0.0.0:*
udp 0 0 0.0.0.0:882 0.0.0.0:*
可以看到udp處有「0.0.0.0:8888」的內容,說明服務程式已經正常執行,可以接收主機上任何ip位址且埠為8888的資料。
如果這時再執行./udpserv &命令,就會看到如下資訊:
bind error: address already in use
說明已經有乙個服務程式在執行了。
3、執行udp client程式
執行./udpclient 127.0.0.1命令來啟動客戶程式,使用127.0.0.1來連線服務程式,執行效果如下:
hello, world!
hello, world!
this is a test
this is a test
^d輸入的資料都正確從服務程式返回了,按ctrl+d可以結束輸入,退出程式。
如果服務程式沒有啟動,而執行客戶程式,就會看到如下資訊:
$ ./udpclient 127.0.0.1
test
read error: connection refused
說明指定的ip位址和埠沒有服務程式繫結,客戶程式就退出了。這就是使用connect()的好處,注意,這裡錯誤資訊是在向服務程式傳送資料後收到 的,而不是在呼叫connect()時。如果你使用tcpdump程式來抓包,會發現收到的是icmp的錯誤資訊。
Linux下的UDP連線程式設計
udp是無連線不可靠的ip協議,和tcp有所不同。udp伺服器呼叫socket bind listen 完成套接字初始化後,呼叫accept 阻塞等待處於監聽埠的狀態。udp客戶端呼叫socket 初始化後,呼叫connect 傳送syn欄位並阻塞等待應答。客戶端如果一直與服務端連線,服務端退出後重...
基於Linux下的UDP程式設計
一.linux下udp程式設計框架 使用udp進行程式設計可以分為客戶端和伺服器端兩部分。1.伺服器端程式包括 建立套接字 將套接字位址結構進行繫結 讀寫資料 關閉套接字 2.客戶端程式包括 建立套接字 讀寫資料 關閉套接字 3.伺服器端和客戶端程式之間的差別 伺服器端和客戶端兩個流程之間的主要差別...
Linux下socket程式設計之UDP
如下 udp client.c include include include include include include include static void usage char proc int main int argc,char argv int sock socket af ine...