TCP/IP 协议栈 -- 编写UDP客户端注意细节
上節我們說到了TCP 客戶端編寫的主要細節, 本節我們來看一下UDP client的幾種情況,測試代碼如下:
server:
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 進程沒有打開
這里 以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客户端注意细节的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pytorch实现NS方程求解-基础PI
- 下一篇: android四大组件共性,Androi