上节我们说到了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的可读是否超时。时间可稍微长一些。

TCP/IP 协议栈 -- 编写UDP客户端注意细节的更多相关文章

  1. TCP/IP协议栈与数据包封装+TCP与UDP区别

    ISO制定的OSI参考模型的过于庞大.复杂招致了许多批评.与此对照,由技术人员自己开发的TCP/IP协议栈获得了更为广泛的应用.如图2-1所示,是TCP/IP参考模型和OSI参考模型的对比示意图. T ...

  2. -1-7 java 网络编程基本知识点 计算机网络 TCP/IP协议栈 通信必备 tcp udp

    计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来, 在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统. 网络编程 ...

  3. tcp/ip网络里的客户端和服务器端 信息交流 与 安全

    ISP(Internet Service Provider) 互联网服务提供商, 即向广大用户综合提供互联网接入业务.信息业务.和增值业务的电信运营商. 通过wireshark学习tcp/ip. 用w ...

  4. 渣渣小本求职复习之路每天一博客系列——TCP/IP协议栈(5)

    前情回顾:一篇短短的博客明显不能满足TCP和UDP这两个饥渴的汉子,而且还被应用协议占了一小半的篇幅.在昨天结束之后,相信大家都基本对TCP/IP协议栈的轮廓有一个大概的印象了,能够对整体有所把握. ...

  5. TCP/IP 协议栈

    TCP(传输控制协议) 传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的.可靠的.基于字节流的传输层通信协议,由IETF的RFC 793定义. 在因特 ...

  6. 计算机网络基础之TCP/IP 协议栈

    计算机网络基础之TCP/IP 协议栈 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.TCP/IP 协议栈概述 1>.什么是TCP/IP协议栈 Transmission C ...

  7. TCP/IP 协议栈4层结构及3次握手4次挥手

    TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输.TCP/IP 协议采用4层结构,分别是应用层.传输层.网络层和链路 ...

  8. 【转载】TCP/IP协议栈

    TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输.TCP/IP 协议采用4层结构,分别是应用层.传输层.网络层和链路 ...

  9. TCP/IP协议栈在Linux内核中的运行时序分析

    网络程序设计调研报告 TCP/IP协议栈在Linux内核中的运行时序分析 姓名:柴浩宇 学号:SA20225105 班级:软设1班 2021年1月 调研要求 在深入理解Linux内核任务调度(中断处理 ...

随机推荐

  1. 前端页面中如何在窗口缩放时让两个div始终在同一行显示

    直接贴代码吧 先总结一下吧  有两种方法 一    最外层设置一个大div  给这个大div固定的宽度和高度 给里面两个小div 设置浮动  设置宽高 <!DOCTYPE html> &l ...

  2. hibernate的集合映射(详细笔记)

  3. Problem V

    Problem Description The aspiring Roy the Robber has seen a lot of American movies, and knows that th ...

  4. Problem W

    Problem Description Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了.要申请国外的任何大学,你都要交纳一定的申请费用 ...

  5. Fibonacci Check-up

    Fibonacci Check-up Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...

  6. 工控SCADA模型 基于HTML5 Canvas WebGL制作摩托车

    工业方面制作图表,制作模型方面运用到 3d 模型是非常多的,在一个大的环境中,构建无数个相同的或者不同的模型,构建起来对于程序员来说也是一件相当头疼的事情,我们利用 HT 帮大家解决了很大的难题,以下 ...

  7. Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.AccessControlException):

    用windows连接hadoop集群执行mapreduce任务的时候出现以下错误: org.apache.hadoop.security.AccessControlException:Permissi ...

  8. javascript中原型链与instanceof 原理

    instanceof:用来判断实例是否是属于某个对象,这个判断依据是什么呢? 首先,了解一下javascript中的原型继承的基础知识: javascript中的对象都有一个__proto__属性,这 ...

  9. number 类型转换 符号

    function convert(sValue, sDataType) {   switch(sDataType) {      case “int”:          return parseIn ...

  10. RestSharp使用总结

    RestSharp是一个轻量的,不依赖任何第三方的组件或者类库的Http的组件.RestSharp具有以下的优点:   1.支持.NET 3.5+,Silverlight 4, Windows Pho ...