基於UDP的伺服器端和客戶端

2021-09-24 19:49:06 字數 2893 閱讀 9046

前面的文章中我們給出了幾個 tcp 的例子,對於 udp 而言,只要能理解前面的內容,實現並非難事。

udp 不像 tcp,無需在連線狀態下交換資料,因此基於 udp 的伺服器端和客戶端也無需經過連線過程。也就是說,不必呼叫 listen() 和 accept() 函式。udp 中只有建立套接字的過程和資料交換的過程。

tcp 中,套接字是一對一的關係。如要向 10 個客戶端提供服務,那麼除了負責監聽的套接字外,還需要建立 10 套接字。但在 udp 中,不管是伺服器端還是客戶端都只需要 1 個套接字。之前解釋 udp 原理的時候舉了郵寄包裹的例子,負責郵寄包裹的快遞公司可以比喻為 udp 套接字,只要有 1 個快遞公司,就可以通過它向任意位址郵寄包裹。同樣,只需 1 個 udp 套接字就可以向任意主機傳送資料。

建立好 tcp 套接字後,傳輸資料時無需再新增位址資訊,因為 tcp 套接字將保持與對方套接字的連線。換言之,tcp 套接字知道目標位址資訊。但 udp 套接字不會保持連線狀態,每次傳輸資料都要新增目標位址資訊,這相當於在郵寄包裹前填寫收件人位址。

傳送資料使用 sendto() 函式:

ssize_t sendto(int sock, void *buf, size_t nbytes, int flags, struct sockaddr *to, socklen_t addrlen); //linux

int sendto(socket sock, const char *buf, int nbytes, int flags, const struct sockadr *to, int addrlen); //windows

linux 和 windows 下的 sendto() 函式類似,下面是詳細引數說明:

udp 傳送函式 sendto() 與tcp傳送函式 write()/send() 的最大區別在於,sendto() 函式需要向他傳遞目標位址資訊。

接收資料使用 recvfrom() 函式:

ssize_t recvfrom(int sock, void *buf, size_t nbytes, int flags, struct sockadr *from, socklen_t *addrlen); //linux

int recvfrom(socket sock, char *buf, int nbytes, int flags, const struct sockaddr *from, int *addrlen); //windows

由於 udp 資料的傳送端不定,所以 recvfrom() 函式定義為可接收傳送端資訊的形式,具體引數如下:

下面結合之前的內容實現回聲客戶端。需要注意的是,udp 不同於 tcp,不存在請求連線和受理過程,因此在某種意義上無法明確區分伺服器端和客戶端,只是因為其提供服務而稱為伺服器端,希望各位讀者不要誤解。

下面給出 windows 下的**,linux 與此類似,不再贅述。

伺服器端 server.cpp:

#include 

#include

#pragma comment (lib, "ws2_32.lib") //載入 ws2_32.dll

#define buf_size 100

int main()

closesocket(sock);

wsacleanup();

return 0;

}**說明:

1) 第 12 行**在建立套接字時,向 socket() 第二個引數傳遞 sock_dgram,以指明使用 udp 協議。

2) 第 18 行**中使用htonl(inaddr_any)來自動獲取 ip 位址。

利用常數 inaddr_any 自動獲取 ip 位址有乙個明顯的好處,就是當軟體安裝到其他伺服器或者伺服器 ip 位址改變時,不用再更改原始碼重新編譯,也不用在啟動軟體時手動輸入。而且,如果一台計算機中已分配多個 ip 位址(例如路由器),那麼只要埠號一致,就可以從不同的 ip 位址接收資料。所以,伺服器中優先考慮使用 inaddr_any;而客戶端中除非帶有一部分伺服器功能,否則不會採用。

客戶端 client.cpp:

#include 

#include

#pragma comment(lib, "ws2_32.lib") //載入 ws2_32.dll

#define buf_size 100

int main();

printf("input a string: ");

gets(buffer);

sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&servaddr, sizeof(servaddr));

int strlen = recvfrom(sock, buffer, buf_size, 0, &fromaddr, &addrlen);

buffer[strlen] = 0;

printf("message form server: %s\n", buffer);

}closesocket(sock);

wsacleanup();

return 0;

}先執行 server,再執行 client,client 輸出結果為:

input a string: c語言中文網

message form server: c語言中文網

input a string: c.biancheng.net founded in 2012

message form server: c.biancheng.net founded in 2012

input a string:

從**中可以看出,server.cpp 中沒有使用 listen() 函式,client.cpp 中也沒有使用 connect() 函式,因為 udp 不需要連線。

基於UDP的伺服器端和客戶端

前面的文章中我們給出了幾個tcp的例子,對於udp而言,只要能理解前面的內容,實現並非難事。udp不像tcp,無需在連線狀態下交換資料,因此基於udp的伺服器端和客戶端也無需經過連線過程。也就是說,不必呼叫 listen 和 accept 函式。udp中只有建立套接字的過程和資料交換的過程。tcp中...

基於UDP的伺服器端和客戶端

前面我們想過了tcp方式的,現在我們說下udp套接字的方式,內容較少,但是很實用。下面通過信件說明udp的工作原理,這是講解udp時使用的傳統示例,它與udp特性完全相符。寄信前應先在信封上填好寄信人和收信人的位址,之後貼上郵票放進郵筒即可。當然,信件的特點使我們無法確認對方是否收到。另外,郵寄過程...

6 1 基於UDP的伺服器端 客戶端

1.udp套接字原理 可靠性方面來說,tcp的確比udp好,但是udp的結構比tcp簡潔,不會傳送類似ack應答訊息,也不會有seq序號,效能有時比tcp高出很多。同時區分tcp和udp的重要標誌是流控制 tcp的生命在於流控制。圖中,ip的作用是讓離開主機b的udp資料報準確傳送到主機 但是最終交...