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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

TCP/IP 协议栈 -- 编写UDP客户端注意细节

發(fā)布時(shí)間:2023/12/20 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TCP/IP 协议栈 -- 编写UDP客户端注意细节 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上節(jié)我們說到了TCP 客戶端編寫的主要細(xì)節(jié), 本節(jié)我們來看一下UDP client的幾種情況,測試代碼如下:
server:

#include <stdio.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/stat.h> #include <sys/types.h> #include <string.h> #define PORT 6666 int main() {int serverfd = socket(AF_INET, SOCK_DGRAM, 0);if(serverfd < 0)return -1;struct sockaddr_in serveraddr;serveraddr.sin_port = htons(PORT);serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);bind(serverfd, (const struct sockaddr *)&serveraddr, sizeof(serveraddr));char buff[256] = {0};struct sockaddr_in clientaddr;socklen_t len = sizeof(clientaddr);while(1){recvfrom(serverfd, buff, 256, 0, (struct sockaddr *)&clientaddr, &len);printf("RECV: %s\n", inet_ntoa( clientaddr.sin_addr));printf("TEXT: %s\n", buff);memset(buff, 0, 256);sendto(serverfd, "recvd hello", 20, 0, (const struct sockaddr*)&clientaddr, sizeof(clientaddr));}return 0; }

client:

#include <stdio.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/stat.h> #include <sys/types.h> #include <string.h> #include <unistd.h> #define PORT 6666 int main(int argc, char *argv[]) {if(argc != 2){fprintf(stderr, "+++ IPaddress\n");return -1;}int clientfd = socket(AF_INET, SOCK_DGRAM, 0);if(clientfd < 0)return -1;struct sockaddr_in serveraddr;serveraddr.sin_port = htons(PORT);serveraddr.sin_family = AF_INET;char *buff = "hello world";size_t n = strlen(buff);char rebuff[256] = {0};if(inet_pton(AF_INET, argv[1], (void *)&serveraddr.sin_addr) == 0){printf("IP address error\n");return -1;}socklen_t len = sizeof(serveraddr);while(1){sleep(2);sendto(clientfd, buff, n, 0, (const struct sockaddr *)&serveraddr, len);recvfrom(clientfd, rebuff, 256, 0, NULL, NULL);printf("SERVER :%s\n", rebuff);}return 0; }

UDP 無連接 不可靠的協(xié)議 它并不會(huì)向TCP一樣會(huì)建立連接后再發(fā)送數(shù)據(jù)。
1.server 進(jìn)程沒有打開

Desktop# tcpdump -i lo -A -e -nn tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes 12:43:03.656237 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 53: 127.0.0.1.46066 > 127.0.0.1.6666: UDP, length 11 E..'..@.@.#$........... ...&hello world 12:43:03.656275 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 81: 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 udp port 6666 unreachable, length 47 E..C%p..@.V.................E..'..@.@.#$........... ...&hello world

這里 以127地址 做實(shí)驗(yàn) 這里可以看到 若主機(jī)server進(jìn)程沒有打開,則client會(huì)阻塞在recvfrom處 這里可以在sendto和 recvfrom 之間插入printf進(jìn)行測試。 這就是UDP的特性, ICMP其實(shí)是sendto造成的它是一個(gè)異步錯(cuò)誤 但是這個(gè)ICMP并沒有返回到應(yīng)用程序, client 并不知道。 這里的解決方案就是用connect 這里的connect與TCP里的connect建立三次握手差別很大, 對于UDP它就是為了收取這個(gè)內(nèi)核接到的這個(gè)ICMP錯(cuò)誤。 內(nèi)核只是檢查是否存在立即可知的錯(cuò)誤,記錄對端的IP地址和端口號,然后立即返回到調(diào)用進(jìn)程。那么這里就要注意到connect里面?zhèn)魅雜erver的ip和port,那么這里的sendto和recvfrom就不要在傳入iP和port, 那么就可以用read和write來代替。 這里還有一點(diǎn)就是因?yàn)閁DP是無連接的, connect并不會(huì)像tcp一樣會(huì)發(fā)送SYN, TCP發(fā)送SYN時(shí),若server進(jìn)程沒有開啟那么會(huì)立即受到RST, 但對于UDP來說 當(dāng)write 后才會(huì)收到主機(jī)的ICMP錯(cuò)誤。

2.server 主機(jī)不存在。

Desktop# tcpdump -i eth0 -A -e -nn host 15.15.12.13 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 13:11:25.331059 00:0c:29:61:1a:9b > 00:1e:2a:67:f3:2e, ethertype IPv4 (0x0800), length 53: 192.168.1.2.44646 > 15.15.12.13.6666: UDP, length 11 .f.'".@.@.;........ ....hello world 13:11:25.331233 00:0c:29:61:1a:9b > 00:1e:2a:67:f3:2e, ethertype IPv4 (0x0800), length 60: 192.168.1.2.44646 > 15.15.12.13.6666: UDP, length 11 .f.'".@.@.;........ ....hello world.......

這里可以看到一直阻塞在recvfrom這里 這里的解決方案就是在recvfrom添加超時(shí)中斷,alarm 或者 select檢測fd是否可讀 設(shè)立超時(shí)。

3.client 正在發(fā)送數(shù)據(jù), server 進(jìn)程被kill掉

13:17:29.059557 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 62: 127.0.0.1.6666 > 127.0.0.1.57718: UDP, length 20 E..0r.@.@............ .v.../recvd hello.......;4 13:17:31.059842 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 53: 127.0.0.1.57718 > 127.0.0.1.6666: UDP, length 11 E..'s.@.@............v. ...&hello world 13:17:31.059922 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 81: 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 udp port 6666 unreachable, length 47 E..C....@.............qs....E..'s.@.@............v. ...&hello world

這里可以看到client也收到了ICMP 解決方案同1.

4.client 正在發(fā)生數(shù)據(jù), server 斷電。

13:17:29.059557 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 62: 127.0.0.1.6666 > 127.0.0.1.57718: UDP, length 20 E..0r.@.@............ .v.../recvd hello.......;4 13:17:31.059842 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 53: 127.0.0.1.57718 > 127.0.0.1.6666: UDP, length 11 E..'s.@.@............v. ...&hello world

同樣這里也會(huì)一直阻塞在recvfrom這里 解決方案同2 給recvfrom添加超時(shí) 或 select 檢查fd的可讀是否超時(shí)。時(shí)間可稍微長一些。

轉(zhuǎn)載于:https://www.cnblogs.com/MaAce/p/7755697.html

總結(jié)

以上是生活随笔為你收集整理的TCP/IP 协议栈 -- 编写UDP客户端注意细节的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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