TCP/IP 协议栈 -- 编写UDP客户端注意细节
上節(jié)我們說到了TCP 客戶端編寫的主要細(xì)節(jié), 本節(jié)我們來看一下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 無連接 不可靠的協(xié)議 它并不會(huì)向TCP一樣會(huì)建立連接后再發(fā)送數(shù)據(jù)。
1.server 進(jìn)程沒有打開
這里 以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)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pytorch实现NS方程求解-基础PI
- 下一篇: spring集成 log4j + slf