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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468931.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RuntimeError: Address already in use

问题描述&#xff1a;Pytorch用多张GPU训练时&#xff0c;会报地址已被占用的错误。其实是端口号冲突了。 因此解决方法要么kill原来的进程&#xff0c;要么修改端口号。 在代码里重新配置 torch.distributed.init_process_group()dist_init_method tcp://{master_ip}:{mast…

python读取数据流_python3+pyshark读取wireshark数据包并追踪telnet数据流

一、程序说明本程序有两个要点&#xff0c;第一个要点是读取wireshark数据包(当然也可以从网卡直接捕获改个函数就行)&#xff0c;这个使用pyshark实现。pyshark是tshark的一个python封装&#xff0c;至于tshark可以认为是命令行版的wireshark&#xff0c;随wireshark一起安装。…

Windows环境下的安装gcc

Windows具有良好的界面和丰富的工具&#xff0c;所以目前linux开发的流程是&#xff0c;windows下完成编码工作&#xff0c;linux上实现编译工作。 为了提高工作效率&#xff0c;有必要在windows环境下搭建一套gcc,gdb,make环境。 MinGW就是windows下gcc的版本。 下载地址ht…

RuntimeError: NCCL error in:XXX,unhandled system error, NCCL version 2.7.8

项目场景&#xff1a; 分布式训练中遇到这个问题&#xff0c; 问题描述 大概是没有启动并行运算&#xff1f;&#xff1f;&#xff1f;&#xff08; 解决方案&#xff1a; &#xff08;1&#xff09;首先看一下服务器GPU相关信息 进入pytorch终端&#xff08;Terminal&#x…

Codeforces Round #371 (Div. 2) C. Sonya and Queries —— 二进制压缩

题目链接&#xff1a;http://codeforces.com/contest/714/problem/C C. Sonya and Queriestime limit per test1 secondmemory limit per test256 megabytesinputstandard inputoutputstandard outputToday Sonya learned about long integers and invited all her friends to …

一张倾斜图片进行矫正 c++_专业性文章:10分钟矫正骨盆前倾

如今&#xff0c;骨盆前倾(又称“下交叉综合征”)非常多&#xff0c;大部分是由于以下两个原因而变得越来越突出&#xff1a;经常久坐不良的运动习惯后面我们讲到纠正骨盆前倾的四个基本步骤&#xff0c;让你快速解决&#xff0c;提高生活质量知识型和系统型的内容&#xff0c;…

vue.js源码学习分享(五)

//配置项var config {/*** Option merge strategies (used in core/util/options)//选项合并策略*/optionMergeStrategies: Object.create(null),/*** Whether to suppress warnings.//是否抑制警告*/silent: false,/*** Show production mode//生产模式 tip message on boot?…

TypeError: can‘t convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory

项目场景&#xff1a; 运行程序&#xff0c;出现报错信息 TypeError: cant convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.。 Traceback (most recent call last):File "tools/demo.py", line 97, in <module>vi…

Secure CRT 自动记录日志

配置自动log操作如下&#xff1a; 1.options ---> Global Options 2、General->Default Session->Edit Default Settings 3、Terminal->Log File 设置如图上所示 点击 日志 &#xff0c;在选项框中 Log file name中填入路径和命名参数&#xff1a; E:\Log\%Y_%M_…

java 异步调用方法_乐字节Java编程之方法、调用、重载、递归

一、概述方法是指人们在实践过程中为达到一定目的和效果所采取的办法、手段和解决方案。所谓方法&#xff0c;就是解决一类问题的代码的有序组合&#xff0c;是一个功能模块。编程语言中的方法是组合在一起来执行操作语句的集合。例如&#xff0c;System.out.println 方法&…

git clone 从GitHub上下载项目到服务器上运行+创建虚拟环境

1. 基础的Linux命令 可先进入需要放置文件的路径之下 pwd # 可看当前路径 cd …/ #返回上一层目录 cd ./xx/ #进入当前路径下的下一个文件2. GitHub项目clone到服务器上运行 # 复制GitHub页面的链接&#xff0c;在服务器后台输入git clone 命令即可 git clone https://githu…

[笔记] FireDAC DataSet 导入及导出 JSON

刚好需要将 FireDAC DataSet (TFDDataSet, TFDQuery...) 转成 JSON&#xff0c;网上找了一圈&#xff0c;原来从 XE6 开始就支持这个功能了&#xff1a; 储存&#xff1a; DataSet1.SaveToFile(d:\Data.json, TFDStorageFormat.sfJSON); 载入&#xff1a; DataSet1.LoadFromFil…

recovery相关的FAQ总结

一、[FAQ12481]Recovery mode在cache/recovery目录下新建一支文件&#xff0c;重启后&#xff0c;新建文件消失了 [DESCRIPTION] 1、在recovery.cpp文件的最后新建一支文件 /cache/recovery/wetest&#xff1b;并写入内容&#xff1a;welcome to recovery mode&#xff01; 2、…

AttributeError: module ‘torch.jit‘ has no attribute ‘_script_if_tracing‘

项目场景&#xff1a; torvh使用提示 AttributeError: module torch.jit has no attribute _script_if_tracing 原因分析&#xff1a; 解决办法&#xff1a;原因是torch与torchvision版本不匹配导致的&#xff0c;重新安装torchvision即可 解决方案&#xff1a; pip install…

java 调用python_Java平台如何调用Python平台?

1. 问题描述Java平台要调用Pyhon平台已有的算法&#xff0c;为了减少耦合度&#xff0c;采用Pyhon平台提供Restful 接口&#xff0c;Java平台负责来调用&#xff0c;采用HttpJson格式交互。2. 解决方案2.1 JAVA平台侧2.1.1 项目代码public static String invokeAlgorithm(Strin…

C 实现 删除字符串空白符的函数 strtrim

说在前面的话 字符串操作在很多C语言比赛里面都有涉及&#xff0c;最近公众号里面的C语言比赛&#xff0c;都是两个关于字符串操作的题目&#xff0c;希望大家认真看题目。 直接上代码 /*************************************************************************> Fil…

小工具:批量替换文件夹下所有文件内容中的指定词

问题描述&#xff1a; 数据集中的xml信息所标注的文件后缀写错了&#xff0c;应该为jpg&#xff0c;因此需要将所有xml文件的.png修改为.jpg 解决代码&#xff1a; 函数作用&#xff1a;找出某文件夹下的包含指定关键词文件列表&#xff0c;并将关键字修改为目标字并将新内容…

jvm性能监控工具

jvm可能存在的问题&#xff1a; OutOfMemoryError&#xff1a;内存不足 内存泄露 线程死锁 锁竞争(Lock Contention) Java消耗过多的CPU一、jps(java virtual machine process status tool)监控jvm进程转台信息jps [options] [hostid] -m&#xff1a;输出传入…

javascript犀牛书_犀牛书作者:最该忘记的JavaScript特性

作者&#xff1a; 李松峰转发链接&#xff1a;https://mp.weixin.qq.com/s/guAN1Cz2gYfKdBhmUpLyVA前言JavaScript这门语言的第一个演示版差不多就在25年前诞生。没记错的话&#xff0c;25年前的今天&#xff0c;1995年5月10日&#xff0c;星期三&#xff0c;我刚刚过了创造Jav…