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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

TCP/IP网络编程_第6章基于UDP的服务器端/客户端

發(fā)布時(shí)間:2023/12/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TCP/IP网络编程_第6章基于UDP的服务器端/客户端 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

6.1 理解 DUP

我們?cè)诘?章學(xué)習(xí)TCP的過(guò)程中, 還同時(shí)了解了 TCP/IP 協(xié)議. 在4層TCP/IP模型中, 上數(shù)第二層傳輸(Transport)層分為T(mén)CP和UDP這兩種. 數(shù)據(jù)交換過(guò)程可以分為通過(guò)TCP套接字完成的TCP方式和通過(guò)UDP套接字完成的UDP方式.

UDP 套接字的特點(diǎn)

下面通過(guò)信件說(shuō)明 UDP 的工作原理, 這是講解UDP 時(shí)使用的傳統(tǒng)示例, 它與 UDP 特性完全相符. 寄信前應(yīng)在信上填好寄信人和收信人的地址, 之后貼上郵票即可. 當(dāng)然, 信件的特點(diǎn)使我們無(wú)法確認(rèn)對(duì)方是否收到. 另外, 郵寄過(guò)程中也可能發(fā)生信件丟失的情況. 也就是說(shuō), 信件是一種不可靠的傳輸方式. 與之類(lèi)似, UDP 提供的同樣是不可靠的數(shù)據(jù)傳輸服務(wù).

如果只考慮可靠性, TCP 應(yīng)該的確比 UDP 好. 但UDP 在結(jié)構(gòu)上比 TCP 更簡(jiǎn)潔. UDP 不會(huì)發(fā)送類(lèi)似 ACK 的應(yīng)答消息, 也不會(huì)像SEQ那樣給數(shù)據(jù)包分配序號(hào). 因此, UDP的性能有時(shí)比 TCP 高出很多. 編程中實(shí)現(xiàn) UDP 也比 TCP 簡(jiǎn)單. 另外, UDP 的可靠性雖然比不上 TCP , 但也不會(huì)像想象中那么 頻繁地?cái)?shù)據(jù)損毀. 因此, 在更重視性能而非可靠情況下, DUP 是一種很好的選擇.

既然如此, UDP 的作用到底是什么呢? 為了提供可靠的數(shù)據(jù)傳輸服務(wù), TCP 在不可靠的IP層進(jìn)行流控制, 而UDP 就缺少這種流控制機(jī)制.

是的, 流控制是區(qū)分UDP 和TCP 的最重要的標(biāo)志. 但若從 TCP 中除去流控制, 所剩內(nèi)容也屈指可數(shù). 也就是說(shuō), TCP 的生命在于流控制. 第5章講過(guò)的"與對(duì)方套接字連接及斷開(kāi)連接過(guò)程"也是流控制的一部分.

UDP 內(nèi)部工作原理

與TCP 不同, UDP 不會(huì)進(jìn)行流控制. 接下來(lái)具體討論UDP的作用, 如圖 6-1 所示.

從圖6-1中可以看出, IP的作用就是讓離開(kāi)主機(jī)B的UDP數(shù)據(jù)包準(zhǔn)確傳達(dá)到主機(jī)A. 但把UDP包最終交給主機(jī)A的某一UDP套機(jī)字的過(guò)程則是由UDP完成的. UDP最重要的作用就是根據(jù)端口號(hào)傳到主機(jī)的數(shù)據(jù)包交付給最終的UDP套接字.

UDP 的高效使用

雖然貌似大部分網(wǎng)絡(luò)編程都基于TCP實(shí)現(xiàn), 但也有一些是基于UDP實(shí)現(xiàn)的. 接下來(lái)考慮何時(shí)使用UDP 更有效. 講解前希望各位明白, UDP也具有一定的可靠性. 網(wǎng)絡(luò)傳輸特性導(dǎo)致信息丟失頻繁, 可若要傳遞壓縮文件(發(fā)送1萬(wàn)個(gè)數(shù)據(jù)包時(shí), 只要丟失一個(gè)就會(huì)產(chǎn)生問(wèn)題), 則必須使用TCP, 因?yàn)閴嚎s文件只要丟失一部分就很難解壓. 但通過(guò)網(wǎng)絡(luò)實(shí)時(shí)傳輸視頻或音頻時(shí)的情況有所不同. 對(duì)于多媒體數(shù)據(jù)而言, 丟失一部分也沒(méi)有太大問(wèn)題, 這只會(huì)引起短暫的畫(huà)面抖動(dòng)的情況, 對(duì)于多媒體數(shù)據(jù)而言, 丟失一部分沒(méi)有太大問(wèn)題, 這只會(huì)引起短暫的畫(huà)面抖動(dòng), 或出細(xì)微的雜音. 但因?yàn)樾枰峁?shí)時(shí)服務(wù), 速度就成為非常重要的因素. 因此, 第5章的流控制就顯得有些多余, 此時(shí)需要考慮使用 UDP. 但UDP并非每次都快于 TCP, TCP比 UDP 慢的原因有一下兩點(diǎn).

如果收發(fā)的數(shù)據(jù)量小但需要頻繁連接時(shí), UDP比TCP更高效. 有機(jī)會(huì)的話, 希望各位深入學(xué)習(xí)TCP/IP 協(xié)議的內(nèi)容構(gòu)造. C語(yǔ)言程序員懂計(jì)算機(jī)結(jié)構(gòu)和操作系統(tǒng)知識(shí)就能寫(xiě)出更好的程序, 同樣, 網(wǎng)絡(luò)程序員若能深入理解TCP/IP協(xié)議則可大幅度 提高自身實(shí)力.

6.2 實(shí)現(xiàn)基于 UDP 的服務(wù)器端/客戶端

接下來(lái)通過(guò)之前介紹的UDP理論實(shí)現(xiàn)真正的程序. 對(duì)于UDP 而言, 只要理解之前的內(nèi)容, 實(shí)現(xiàn)并非難事.

UDP 中的服務(wù)器端和客戶端沒(méi)有連接

UDP 服務(wù)器端/客戶端不像TCP那樣在連接狀態(tài)下交換數(shù)據(jù), 因此與TCP不同, 無(wú)需經(jīng)過(guò)連接過(guò)程. 也就是說(shuō), 不必調(diào)用TCP 連接過(guò)程中調(diào)用的listen函數(shù)和accept函數(shù). UDP 中只有創(chuàng)建套接字過(guò)程和數(shù)據(jù)交換過(guò)程.

UDP 服務(wù)器端和客戶端均只需1個(gè)套接字

TCP 中, 套接字之間應(yīng)該是一對(duì)一的關(guān)系. 若要向10個(gè)客戶端提供服務(wù), 則除了守門(mén)的服務(wù)器套接字外, 還需要10個(gè)服務(wù)器套接字. 但在UDP 中, 不管是服務(wù)器端還是客戶端都只需要一個(gè)套接字. 之前解析UDP原理是舉例了信件的例子, 收發(fā)信件時(shí)使用的郵箱可以比如為UDP套接字. 只要附近有一個(gè)郵箱, 就可以通過(guò)它向任意地址寄出信件. 同樣, 只需1個(gè)UDP套接字就 可以向任意主機(jī)傳輸數(shù)據(jù), 如圖6-2所示.

圖6-2展示了一個(gè)UDP套接字與2個(gè)不同主機(jī)交換數(shù)據(jù)的過(guò)程. 也就是說(shuō), 只需1個(gè)UDP 套接字就能和多臺(tái)主機(jī)通信.

基于 UDP 的數(shù)據(jù) I/O 函數(shù)

創(chuàng)建好TCP套接字后, 傳輸數(shù)據(jù)時(shí)無(wú)需再添加地址信息. 因?yàn)門(mén)CP 套接字將保持與對(duì)方套接字的連接. 換言之, TCP 套機(jī)字知道目標(biāo)地址信息. 但UDP套接字不會(huì)保持連接狀態(tài)(UDP 套機(jī)字只有簡(jiǎn)單的郵箱功能), 因此每次傳輸數(shù)據(jù)都要添加目標(biāo)地址信息. 這相當(dāng)于寄信中填寫(xiě)地址. 接下來(lái)介紹填寫(xiě)地址并傳輸數(shù)據(jù)時(shí)調(diào)用的UDP相關(guān)函數(shù).

上述函數(shù)與之前的TCP 輸出函數(shù)最大區(qū)別在于, 此函數(shù)需要向它傳遞目標(biāo)地址信息. 接下來(lái)介紹接收UDP數(shù)據(jù)的函數(shù). UDP數(shù)據(jù)的發(fā)送端并不固定, 因此該函數(shù)定義為可接收發(fā)送端信息的形式, 也就是將同時(shí)返回UDP數(shù)據(jù)包中的發(fā)送信息.

編寫(xiě)UDP程序是最核心的部分就在于上述兩個(gè)函數(shù), 這也說(shuō)明二者在UDP 數(shù)據(jù)傳輸中的地位.

基于 UDP 的回聲服務(wù)器端/客戶端

下面結(jié)合之前的內(nèi)容實(shí)現(xiàn)回聲服務(wù)器. 需要注意的是, UDP 不同于 TCP, 不存在請(qǐng)求連接和受理過(guò)程, 因此在某種意義上無(wú)法明確區(qū)分服務(wù)器端和客戶端. 只是因其提供服務(wù)而稱為服務(wù)器端, 希望各位不要誤解.
服務(wù)器端:

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h>#define BUF_SIZE 30void error_handling(char *message);int main(int argc, char *argv[]) {int serv_sock;char message[BUF_SIZE];int str_len;socklen_t clnt_adr_sz;struct sockaddr_in serv_adr, clnt_adr;if (argc != 2){printf("Usage : %s <port>\n", argv[0]);exit(1);}serv_sock = socket(PF_INET, SOCK_DGRAM, 0);if (serv_sock == -1){error_handling("UDP socket creation error");}memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);serv_adr.sin_port = htons(atoi(argv[1]));if (bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1){error_handling("bind() error");}while(1){clnt_adr_sz = sizeof(clnt_adr);str_len = recvfrom(serv_sock, message, BUF_SIZE, 0, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);sendto(serv_sock, message, str_len, 0, (struct sockaddr*)&clnt_adr, clnt_adr_sz);}close(serv_sock);return 0; }void error_handling(char *message) {fputs(message, stderr);fputc('\n', stderr);exit(1); }

客戶端:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <string.h>#define BUF_SIZE 30void error_handlin(char *message);int main(int argc, char *argv[]) {int sock;char message[BUF_SIZE];int str_len;socklen_t adr_sz;struct sockaddr_in serv_adr, from_adr;if (argc != 3){printf("Usage ; %s <IP> <port>\n", argv[0]);exit(1);}sock = socket(PF_INET, SOCK_DGRAM, 0);if (sock == -1){error_handlin("socket() error");}memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = inet_addr(argv[1]);serv_adr.sin_port = htons(atoi(argv[2]));while(1){fputs("Insert message(q to quit): ", stdout);fgets(message, sizeof(message), stdin);if (!strcmp(message, "q\n") || !strcmp(message, "Q\n")){break;}sendto(sock, message, strlen(message), 0, (struct sockaddr*)&serv_adr, sizeof(serv_adr));adr_sz = sizeof(from_adr);str_len = recvfrom(sock, message, BUF_SIZE, 0, (struct sockaddr*)&from_adr, &adr_sz);message[str_len] = 0;printf("Message from server: %s", message);}close(sock);return 0; }void error_handlin(char *message) {fputs(message, stderr);fputc('\n', stderr);exit(1); }

客戶端;’

服務(wù)器端:

運(yùn)行過(guò)程中的順序并不重要. 只需保證在調(diào)用sendto函數(shù)前, sendto函數(shù)的目標(biāo)主機(jī)程序已經(jīng)開(kāi)始運(yùn)行.

UDP 客戶端套接字的地址分配

前面講解了 UDP 服務(wù)器/客戶端的實(shí)現(xiàn)方法. 但如果仔細(xì)觀察 UDP 客戶端會(huì)發(fā)現(xiàn), 它缺少把IP和端口分配的過(guò)程給套接字的過(guò)程. TCP 客戶端調(diào)用connect 函數(shù)自動(dòng)完成此過(guò)程, 而UDP 中連能承擔(dān)相同的函數(shù)語(yǔ)句都沒(méi)有. 究竟在何處分配IP 和 端口號(hào)呢?

UDP 程序中, 調(diào)用sendto函數(shù)傳輸數(shù)據(jù)強(qiáng)應(yīng)完成對(duì)套接字的地址分配工作, 因此調(diào)用bind函數(shù). 當(dāng)然, bind函數(shù)在TCP 程序中出現(xiàn)過(guò), 但bind函數(shù)不區(qū)分和 UDP , 也就是說(shuō), 在UDP 程序中同樣可以調(diào)用. 另外, 如果調(diào)用sendto 函數(shù)時(shí)尚未分配地址信息, 則在首次調(diào)用sendto函數(shù)是給出相應(yīng)的套接字自動(dòng)分配IP和端口. 而且此時(shí)分配的地址一直保留到程序結(jié)束為止, 因此也可用來(lái)與其他UDP 套接字進(jìn)行數(shù)據(jù)交換. 當(dāng)然, IP用主機(jī)IP, 端口號(hào)尚未使用的任意端口號(hào).

綜上所述, 調(diào)用sendto 函數(shù)是自動(dòng)分配IP和端口號(hào), 因此, UDP 客戶端中通常無(wú)需額外的地址分配過(guò)程. 所以之前實(shí)例中省略了該過(guò)程, 這也是普遍的實(shí)現(xiàn)方式.

6.3 UDP 的數(shù)據(jù)傳輸特性和調(diào)用connect 函數(shù)

我們之前通過(guò)實(shí)例驗(yàn)證了TCP傳輸?shù)臄?shù)據(jù)不存在數(shù)據(jù)邊界, 本節(jié)講驗(yàn)證UDP 數(shù)據(jù)傳輸中存在數(shù)據(jù)邊界. 最后討論UDP 中connect 函數(shù)的調(diào)用, 以此結(jié)束UDP 相關(guān)討論.

存在數(shù)據(jù)邊界的 UDP 套接字

前面說(shuō)過(guò)TCP 數(shù)據(jù)傳輸中不存在邊界, 這表示"數(shù)據(jù)傳輸過(guò)程中調(diào)用I/O函數(shù)的次數(shù)不具有任何意義."

相反, UDP 是具有數(shù)據(jù)邊界的協(xié)議, 傳輸中調(diào)用I/O函數(shù)的次數(shù)非常重要. 因此, 輸入函數(shù)的調(diào)用次數(shù)和輸出函數(shù)的調(diào)用次數(shù)完全一致, 這樣才能保證接收全部已發(fā)數(shù)據(jù). 例如, 調(diào)用3次輸出函數(shù)發(fā)送的數(shù)據(jù)必須通過(guò)調(diào)用3次輸入函數(shù)才能接收完. 下面通過(guò)簡(jiǎn)單實(shí)例進(jìn)行驗(yàn)證.

#include <stdlib.h> #include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <sys/socket.h> #include <unistd.h>#define BUF_SIZE 30void error_handling(char *message);int main(int argc, char *argv[]) {int sock;char message[BUF_SIZE];struct sockaddr_in my_adr, your_adr;socklen_t adr_sz;int str_len, i;if (argc != 2){printf("Usage : %s <port> \n", argv[0]);exit(1);}sock = socket(PF_INET, SOCK_DGRAM, 0);if (sock == -1){error_handling("socket() error");}memset(&my_adr, 0, sizeof(my_adr));my_adr.sin_family = AF_INET;my_adr.sin_addr.s_addr = htonl(INADDR_ANY);my_adr.sin_port = htons(atoi(argv[1]));if (bind(sock, (struct sockaddr*)&my_adr, sizeof(my_adr)) == -1){error_handling("bind() error");}for (i=0; i<3; i++){sleep(5);adr_sz = sizeof(your_adr);str_len = recvfrom(sock, message, BUF_SIZE, 0, (struct sockaddr*)&your_adr, &adr_sz);printf("Message %d : %s \n", i+1, message);}close(sock);return 0; }void error_handling(char *message) {fputs(message, stderr);fputc('\n', stderr);exit(1); }

(請(qǐng)到https://www.jiumodiary.com/)
下面本書(shū)
上述實(shí)例中需要各位特別留意的是第30行中的for語(yǔ)句. 首先在第32行中調(diào)用sleep函數(shù), 使程序停頓時(shí)間等于傳遞的時(shí)間(以秒為單位)參數(shù). 也就是說(shuō), 第30行的for循環(huán)中每隔5秒調(diào)用1次recvfrom 函數(shù). 另外還添加了驗(yàn)證函數(shù)調(diào)用次數(shù)的語(yǔ)句. 稍后再講解延遲執(zhí)行程序的原因.

接下來(lái)的實(shí)例向之前的bound_host1.c 傳輸數(shù)據(jù), 該實(shí)例共調(diào)用sendto函數(shù)3次以傳輸字符串?dāng)?shù)據(jù).
客戶端:

#include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/socket.h> #include <unistd.h> #include <arpa/inet.h>void error_handling(char *message);int main(int argc, char *argv[]) {int sock;char msg1[] = "Hi!";char msg2[] = "I'm another UDP host!";char msg3[] = "Nice to meet you";struct sockaddr_in your_adr;socklen_t your_adr_sz;if (argc != 3){printf("Usage : %s <IP> <potr> \n", argv[0]);exit(1);}sock = socket(PF_INET, SOCK_DGRAM, 0);if (sock == -1){error_handling("socket() error");}memset(&your_adr, 0, sizeof(your_adr));your_adr.sin_family = AF_INET;your_adr.sin_addr.s_addr = inet_addr(argv[1]);your_adr.sin_port = htons(atoi(argv[2]));sendto(sock, msg1, sizeof(msg1), 0, (struct sockaddr*)&your_adr, sizeof(your_adr));sendto(sock, msg2, sizeof(msg2), 0, (struct sockaddr*)&your_adr, sizeof(your_adr));sendto(sock, msg3, sizeof(msg3), 0, (struct sockaddr*)&your_adr, sizeof(your_adr));close(sock);return 0; }void error_handling(char *message) {fputs(message, stderr);fputc('\n', stderr);exit(1); }

運(yùn)行結(jié)果:
客戶端:

服務(wù)器端:

證明必須在UDP通信過(guò)程是I/O函數(shù)調(diào)用次數(shù)保存一致.

已連接(connected) UDP 套機(jī)字與未連接(unconnected) UDP 套接字

TCP 套接字中需注冊(cè)待傳輸?shù)哪繕?biāo)IP和端口號(hào), 而UDP中則無(wú)需注冊(cè). 因此, 通過(guò)sendto 函數(shù)傳輸數(shù)據(jù)的過(guò)程大致可分以下3階段.

每次調(diào)用sendto函數(shù)時(shí)重復(fù)上述過(guò)程. 每次都變更目標(biāo)地址. 因此可以重復(fù)利用統(tǒng)一UDP套接字向不同目標(biāo)傳輸數(shù)據(jù). 這種未注冊(cè)目標(biāo)地址信息的套機(jī)字稱為未連接套機(jī)字, 反之, 注冊(cè)了目標(biāo)地址的套機(jī)字稱為連接connected 套接字. 顯然, UDP 套機(jī)字默認(rèn)屬于未連接套機(jī)字, 但UDP套接字在下述情況顯得不太合理:

此時(shí)需要重復(fù)3次上述三階段. 因此, 要與同一主機(jī)進(jìn)行長(zhǎng)時(shí)間通信時(shí), 將UDP套機(jī)字變成已連接套接字會(huì)提高效率. 上述三個(gè)階段中, 第一個(gè)和第三個(gè)階段占整個(gè)通信過(guò)程接近1/3的時(shí)間, 縮短這部分時(shí)間將大大提高整體性能.

創(chuàng)建已連接UDP套接字

創(chuàng)建已連接UDP套接字的過(guò)程格外簡(jiǎn)單, 只需針對(duì)UDP套接字調(diào)用connect函數(shù).

上述代碼看似與TCP套接字創(chuàng)建過(guò)程一致, 但socket函數(shù)的第二個(gè)參數(shù)分明是SOCK_DGRAM. 也就是說(shuō), 創(chuàng)建的的確是UDP套接字. 當(dāng)然, 針對(duì)UDP 套機(jī)字調(diào)用connect 函數(shù)并不意味著要與對(duì)方UDP套機(jī)字連接, 這只是向UDP 套機(jī)字注冊(cè)目標(biāo)IP和端口信息.

之后就與TCP 套機(jī)字一樣, 每次調(diào)用sendto 函數(shù)時(shí)只需傳遞數(shù)據(jù). 因?yàn)橐呀?jīng)指定了收發(fā)對(duì)象, 所以可以使用sendto, recvfrom函數(shù), 還可以使用write, read 函數(shù)進(jìn)行通信.

下列實(shí)例將之前的uecho_client.c 程序改成基于已連接UDP 套機(jī)字的程序, 因此可以結(jié)合uecho_server.c 程序運(yùn)行. 另外, 為便于說(shuō)明, 未直接刪除uecho_client.c 的I/O 函數(shù), 而是添加了注釋.

#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <arpa/inet.h> #include <string.h> #include <unistd.h>#define BUF_SIZE 30 void error_handling(char *message);int main(int argc, char *argv[]) {int sock;char message[BUF_SIZE];int str_len;socklen_t adr_sz; /* 多余變量 */struct sockaddr_in serv_adr, from_adr; /* 不再需要from_adr! */if (argc != 3){printf("Usage : %s <IP> <port> \n", argv[0]);exit(1);}sock = socket(PF_INET, SOCK_DGRAM, 0);if (sock == -1){error_handling("socket() error");}memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = inet_addr(argv[1]);serv_adr.sin_port = htons(atoi(argv[2]));connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr));while(1){fputs("Insert message(q to Q): ", stdout);fgets(message, sizeof(message), stdin);if (!strcmp(message, "q\n") || !strcmp(message, "Q\n")){break;}write(sock, message, strlen(message));str_len = read(sock, message, sizeof(message)-1);message[str_len] = 0;printf("Message from server: %s", message);}close(sock);return 0; }void error_handling(char *message) {fputs(message, stderr);fputc('\n', stderr);exit(1); }

沒(méi)有運(yùn)行結(jié)果和代碼說(shuō)明, 代碼中用write read 函數(shù)代替sendto, recvfrom函數(shù).

6.4 基于Windows 的實(shí)現(xiàn)

首先介紹Windows 平臺(tái)下的sendto 函數(shù)好readfrom 函數(shù), 實(shí)際上與 Linux 的函數(shù)沒(méi)有太大區(qū)別, 但為了各位親自確認(rèn)這一點(diǎn), 這里給出定義.


以上兩個(gè)函數(shù)與 Linux 下的sendto, recvfrom 函數(shù)相比, 其參數(shù)個(gè)數(shù), 順序及含義完全相同, 故省略具體說(shuō)明, 接下來(lái)實(shí)現(xiàn)Windows平臺(tái)下的UDP 回聲服務(wù)器端/客戶端. 其中, 回聲服務(wù)器端是利用已連接UDP 套接字實(shí)現(xiàn)的.
服務(wù)器端

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <WinSock2.h>#define BUF_SIZE 30void ErrorHandling(const char* message);int main(int argc, char* argv[]) {WSADATA wsaData;SOCKET servSock;char message[BUF_SIZE];int strLen;int clntAdrSz;SOCKADDR_IN servAdr, clntAdr;if (argc != 2){printf("Usage : %s <port>\n", argv[0]);exit(1);}if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ErrorHandling("WSAStartup() error");}servSock = socket(PF_INET, SOCK_DGRAM, 0);if (servSock == INVALID_SOCKET){ErrorHandling("socket() error");}memset(&servAdr, 0, sizeof(servAdr));memset(&clntAdr, 0, sizeof(clntAdr));servAdr.sin_family = AF_INET;servAdr.sin_addr.s_addr = htonl(INADDR_ANY);servAdr.sin_port = htons(atoi(argv[1]));if (bind(servSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR){ErrorHandling("bind() error");}while (1){clntAdrSz = sizeof(clntAdr);strLen = recvfrom(servSock, message, BUF_SIZE, 0, (SOCKADDR*)&clntAdr, &clntAdrSz);sendto(servSock, message, strLen, 0, (SOCKADDR*)&clntAdr, sizeof(clntAdr));}closesocket(servSock);WSACleanup();return 0; }void ErrorHandling(const char* message) {fputs(message, stderr);fputc('\n', stderr);exit(1); }

客戶端:

#include <stdio.h> #include <stdlib.h> #include <WinSock2.h> #include <string.h>#define BUF_SIZE 30void ErrorHandling(const char* message);int main(int argc, char* argv[]) {WSADATA wsaData;SOCKET sock;char message[BUF_SIZE];int strLen;SOCKADDR_IN servAdr;if (argc != 3){printf("Usage : %s <IP> <port> \n", argv[0]);exit(1);}if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ErrorHandling("WSAStartup() error");}sock = socket(PF_INET, SOCK_DGRAM, 0);if (sock == INVALID_SOCKET){ErrorHandling("socket() error");}memset(&servAdr, 0, sizeof(servAdr));servAdr.sin_family = AF_INET;servAdr.sin_addr.s_addr = inet_addr(argv[1]);servAdr.sin_port = htons(atoi(argv[2]));connect(sock, (SOCKADDR*)&servAdr, sizeof(servAdr));while (1){fputs("Insert message(q to quit): ", stdout);fgets(message, sizeof(message), stdin);if (!strcmp(message, "q\n") || !strcmp(message, "Q\n")){break;}send(sock, message, strlen(message), 0);strLen = recv(sock, message, sizeof(message) - 1, 0);message[strLen] = 0;printf("Message from server: %s", message);}closesocket(sock);WSACleanup();return 0; }void ErrorHandling(const char* message) {fputs(message, stderr);fputc('\n', stderr);exit(1); }

運(yùn)行結(jié)果:
客戶端:

上述客戶端實(shí)例利用已連接UDP套接字進(jìn)行輸入輸出, 因此用send, recv 函數(shù)替代sendto , recvfrom 函數(shù). 此外也如實(shí)反映了已連接UDP 套接字的好處.

結(jié)語(yǔ):

你可以在下面這個(gè)網(wǎng)站, 下載這本書(shū)
https://www.jiumodiary.com

時(shí)間: 2020-05-30

總結(jié)

以上是生活随笔為你收集整理的TCP/IP网络编程_第6章基于UDP的服务器端/客户端的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产精品一区二区三区四区在线观看 | 免费av网站在线播放 | 黄色高潮视频 | 久久噜噜色综合一区二区 | 日本成人黄色 | 古代黄色片 | 成人在线观看一区二区 | 91成人在线免费视频 | 蜜桃精品在线 | 一区二区三区不卡视频在线观看 | 国产高清www| 日本不卡一二三 | 夜夜春夜夜爽 | 精品人妻无码一区 | 嫩草在线播放 | 日韩精品久久久久久久电影99爱 | www.youji.com| 久久精品网址 | 欧美精品h| 少妇精品高潮欲妇又嫩中文字幕 | 一区二区三区在线视频播放 | 视频在线观看网站免费 | 欧美日韩三级 | 国产偷人 | 欧美一区二区三区四区五区六区 | 国产精品美女久久久久 | 国产91区| 夜夜嗨av一区二区三区网页 | 奇米精品一区二区三区四区 | 国产精品一区无码 | 一区二区三区四区五区av | 精精国产 | 色噜噜网站 | 日韩三级黄色 | 丁香在线视频 | 国产在线看一区 | 日韩成人免费在线观看 | 欧美a√在线 | 69色视频 | 黑人乱码一区二区三区av | 上海毛片 | 乱亲女h秽乱长久久久 | 嫦娥性艳史bd | 国产精自产拍久久久久久蜜 | 国产成人精品网 | 成年网站免费在线观看 | 蜜桃成人网 | 亚洲欧美999 | 一级aaaa毛片 | 国产精品mm | 欧美成人三级在线视频 | 久久国产亚洲 | 成年人视频在线看 | 国产高清99| 欧美性开放视频 | 欧美猛操 | 日韩成人av网 | 精品午夜视频 | 黄色免费视频观看 | 亚洲一级网站 | 日韩影院一区 | 超污视频网站 | 亚洲女人天堂色在线7777 | 男人操女人动态图 | 亚洲综合视频网站 | 日本少妇xxxxx | 色图综合网 | 天天夜夜草 | 国产精品久久久久久无人区 | 无码精品人妻一区二区三区影院 | 蜜桃视频免费网站 | 99色在线视频 | 高清一区二区三区 | 伊人av综合网 | 国产超91| 韩国精品av | 韩日免费av | 免费看黄在线观看 | 97视频在线看 | 99热精品久久 | 狠狠干2022 | 自拍偷拍99 | 国产免费视屏 | 曰批又黄又爽免费视频 | 激情小说专区 | 久久这里只有精品国产 | 三级伦理片 | 免费国产视频 | 在线中文字幕av | 亚洲精品一区在线观看 | 日韩欧美在线一区二区三区 | 日批视频在线 | 国产在线麻豆 | 日本a v网站| 麻豆成人网| 男人的天堂一区二区 | 欧美黑吊大战白妞欧美大片 | 亚洲久久色 | 超碰人人搞 |