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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

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

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

上節我們說到了TCP 客戶端編寫的主要細節, 本節我們來看一下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 無連接 不可靠的協議 它并不會向TCP一樣會建立連接后再發送數據。
1.server 進程沒有打開

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地址 做實驗 這里可以看到 若主機server進程沒有打開,則client會阻塞在recvfrom處 這里可以在sendto和 recvfrom 之間插入printf進行測試。 這就是UDP的特性, ICMP其實是sendto造成的它是一個異步錯誤 但是這個ICMP并沒有返回到應用程序, client 并不知道。 這里的解決方案就是用connect 這里的connect與TCP里的connect建立三次握手差別很大, 對于UDP它就是為了收取這個內核接到的這個ICMP錯誤。 內核只是檢查是否存在立即可知的錯誤,記錄對端的IP地址和端口號,然后立即返回到調用進程。那么這里就要注意到connect里面傳入server的ip和port,那么這里的sendto和recvfrom就不要在傳入iP和port, 那么就可以用read和write來代替。 這里還有一點就是因為UDP是無連接的, connect并不會像tcp一樣會發送SYN, TCP發送SYN時,若server進程沒有開啟那么會立即受到RST, 但對于UDP來說 當write 后才會收到主機的ICMP錯誤。

2.server 主機不存在。

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添加超時中斷,alarm 或者 select檢測fd是否可讀 設立超時。

3.client 正在發送數據, server 進程被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 正在發生數據, 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

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

轉載于:https://www.cnblogs.com/MaAce/p/7755697.html

總結

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

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