日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于UDP的服务器端和客户端

發布時間:2025/3/12 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于UDP的服务器端和客户端 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

UDP中的服務器端和客戶端沒有連接

UDP 不像 TCP,無需在連接狀態下交換數據,因此基于 UDP 的服務器端和客戶端也無需經過連接過程。也就是說,不必調用 listen() 和 accept() 函數。UDP 中只有創建套接字的過程和數據交換的過程。

UDP服務器端和客戶端均只需1個套接字

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

基于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() 函數類似,下面是詳細參數說明:

    • sock:用于傳輸 UDP 數據的套接字;
    • buf:保存待傳輸數據的緩沖區地址;
    • nbytes:帶傳輸數據的長度(以字節計);
    • flags:可選項參數,若沒有可傳遞 0;
    • to:存有目標地址信息的 sockaddr 結構體變量的地址;
    • addrlen:傳遞給參數 to 的地址值結構體變量的長度。


    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() 函數定義為可接收發送端信息的形式,具體參數如下:

    • sock:用于接收 UDP 數據的套接字;
    • buf:保存接收數據的緩沖區地址;
    • nbytes:可接收的最大字節數(不能超過 buf 緩沖區的大小);
    • flags:可選項參數,若沒有可傳遞 0;
    • from:存有發送端地址信息的 sockaddr 結構體變量的地址;
    • addrlen:保存參數 from 的結構體變量長度的變量地址值。

    基于UDP的回聲服務器端/客戶端

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

    下面給出 Windows 下的代碼,Linux 與此類似,不再贅述。

    服務器端 server.cpp:

  • #include <stdio.h>
  • #include <winsock2.h>
  • #pragma comment (lib, "ws2_32.lib") //加載 ws2_32.dll
  • ?
  • #define BUF_SIZE 100
  • ?
  • int main(){
  • WSADATA wsaData;
  • WSAStartup( MAKEWORD(2, 2), &wsaData);
  • ?
  • //創建套接字
  • SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
  • ?
  • //綁定套接字
  • sockaddr_in servAddr;
  • memset(&servAddr, 0, sizeof(servAddr)); //每個字節都用0填充
  • servAddr.sin_family = PF_INET; //使用IPv4地址
  • servAddr.sin_addr.s_addr = htonl(INADDR_ANY); //自動獲取IP地址
  • servAddr.sin_port = htons(1234); //端口
  • bind(sock, (SOCKADDR*)&servAddr, sizeof(SOCKADDR));
  • ?
  • //接收客戶端請求
  • SOCKADDR clntAddr; //客戶端地址信息
  • int nSize = sizeof(SOCKADDR);
  • char buffer[BUF_SIZE]; //緩沖區
  • while(1){
  • int strLen = recvfrom(sock, buffer, BUF_SIZE, 0, &clntAddr, &nSize);
  • sendto(sock, buffer, strLen, 0, &clntAddr, nSize);
  • }
  • ?
  • 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 <stdio.h>
  • #include <WinSock2.h>
  • #pragma comment(lib, "ws2_32.lib") //加載 ws2_32.dll
  • ?
  • #define BUF_SIZE 100
  • ?
  • int main(){
  • //初始化DLL
  • WSADATA wsaData;
  • WSAStartup(MAKEWORD(2, 2), &wsaData);
  • ?
  • //創建套接字
  • SOCKET sock = socket(PF_INET, SOCK_DGRAM, 0);
  • ?
  • //服務器地址信息
  • sockaddr_in servAddr;
  • memset(&servAddr, 0, sizeof(servAddr)); //每個字節都用0填充
  • servAddr.sin_family = PF_INET;
  • servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  • servAddr.sin_port = htons(1234);
  • ?
  • //不斷獲取用戶輸入并發送給服務器,然后接受服務器數據
  • sockaddr fromAddr;
  • int addrLen = sizeof(fromAddr);
  • while(1){
  • char buffer[BUF_SIZE] = {0};
  • 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的服务器端和客户端的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。