1. <wbr id="m8vu6"></wbr>

      <del id="m8vu6"><center id="m8vu6"><source id="m8vu6"></source></center></del>
        <p id="m8vu6"><sub id="m8vu6"></sub></p>

        VB.net 2010 視頻教程 VB.net 2010 視頻教程 VB.net 2010 視頻教程
        SQL Server 2008 視頻教程 c#入門經典教程 Visual Basic從門到精通視頻教程
        當前位置:
        首頁 > 硬件網絡 > 網絡工程師 >
        • 基于UDP的服務器端和客戶端

        • 2019-11-13 21:03 來源:未知
        前面的文章中我們給出了幾個 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() 函數:
        
        		
        1. ssize_t sendto(int sock, void *buf, size_t nbytes, int flags, struct sockaddr *to, socklen_t addrlen); //Linux
        2. 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() 函數:
        
        		
        1. ssize_t recvfrom(int sock, void *buf, size_t nbytes, int flags, struct sockadr *from, socklen_t *addrlen); //Linux
        2. 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:
        
        		
        1. #include <stdio.h>
        2. #include <winsock2.h>
        3. #pragma comment (lib, "ws2_32.lib") //加載 ws2_32.dll
        4.  
        5. #define BUF_SIZE 100
        6.  
        7. int main(){
        8. WSADATA wsaData;
        9. WSAStartup( MAKEWORD(2, 2), &wsaData);
        10.  
        11. //創建套接字
        12. SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
        13.  
        14. //綁定套接字
        15. sockaddr_in servAddr;
        16. memset(&servAddr, 0, sizeof(servAddr)); //每個字節都用0填充
        17. servAddr.sin_family = PF_INET; //使用IPv4地址
        18. servAddr.sin_addr.s_addr = htonl(INADDR_ANY); //自動獲取IP地址
        19. servAddr.sin_port = htons(1234); //端口
        20. bind(sock, (SOCKADDR*)&servAddr, sizeof(SOCKADDR));
        21.  
        22. //接收客戶端請求
        23. SOCKADDR clntAddr; //客戶端地址信息
        24. int nSize = sizeof(SOCKADDR);
        25. char buffer[BUF_SIZE]; //緩沖區
        26. while(1){
        27. int strLen = recvfrom(sock, buffer, BUF_SIZE, 0, &clntAddr, &nSize);
        28. sendto(sock, buffer, strLen, 0, &clntAddr, nSize);
        29. }
        30.  
        31. closesocket(sock);
        32. WSACleanup();
        33. return 0;
        34. }
        代碼說明: 1) 第 12 行代碼在創建套接字時,向 socket() 第二個參數傳遞 SOCK_DGRAM,以指明使用 UDP 協議。 2) 第 18 行代碼中使用htonl(INADDR_ANY)來自動獲取 IP 地址。 利用常數 INADDR_ANY 自動獲取 IP 地址有一個明顯的好處,就是當軟件安裝到其他服務器或者服務器 IP 地址改變時,不用再更改源碼重新編譯,也不用在啟動軟件時手動輸入。而且,如果一臺計算機中已分配多個 IP 地址(例如路由器),那么只要端口號一致,就可以從不同的 IP 地址接收數據。所以,服務器中優先考慮使用 INADDR_ANY;而客戶端中除非帶有一部分服務器功能,否則不會采用。 客戶端 client.cpp:
        
        		
        1. #include <stdio.h>
        2. #include <WinSock2.h>
        3. #pragma comment(lib, "ws2_32.lib") //加載 ws2_32.dll
        4.  
        5. #define BUF_SIZE 100
        6.  
        7. int main(){
        8. //初始化DLL
        9. WSADATA wsaData;
        10. WSAStartup(MAKEWORD(2, 2), &wsaData);
        11.  
        12. //創建套接字
        13. SOCKET sock = socket(PF_INET, SOCK_DGRAM, 0);
        14.  
        15. //服務器地址信息
        16. sockaddr_in servAddr;
        17. memset(&servAddr, 0, sizeof(servAddr)); //每個字節都用0填充
        18. servAddr.sin_family = PF_INET;
        19. servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        20. servAddr.sin_port = htons(1234);
        21.  
        22. //不斷獲取用戶輸入并發送給服務器,然后接受服務器數據
        23. sockaddr fromAddr;
        24. int addrLen = sizeof(fromAddr);
        25. while(1){
        26. char buffer[BUF_SIZE] = {0};
        27. printf("Input a string: ");
        28. gets(buffer);
        29. sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&servAddr, sizeof(servAddr));
        30. int strLen = recvfrom(sock, buffer, BUF_SIZE, 0, &fromAddr, &addrLen);
        31. buffer[strLen] = 0;
        32. printf("Message form server: %s\n", buffer);
        33. }
        34.  
        35. closesocket(sock);
        36. WSACleanup();
        37. return 0;
        38. }
        先運行 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 不需要連接。
        相關教程
        免费看成年人视频大全_免费看成年人视频在线观看