上节我们说到了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客户端注意细节的更多相关文章
-
TCP/IP协议栈与数据包封装+TCP与UDP区别
ISO制定的OSI参考模型的过于庞大.复杂招致了许多批评.与此对照,由技术人员自己开发的TCP/IP协议栈获得了更为广泛的应用.如图2-1所示,是TCP/IP参考模型和OSI参考模型的对比示意图. T ...
-
-1-7 java 网络编程基本知识点 计算机网络 TCP/IP协议栈 通信必备 tcp udp
计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来, 在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统. 网络编程 ...
-
tcp/ip网络里的客户端和服务器端 信息交流 与 安全
ISP(Internet Service Provider) 互联网服务提供商, 即向广大用户综合提供互联网接入业务.信息业务.和增值业务的电信运营商. 通过wireshark学习tcp/ip. 用w ...
-
渣渣小本求职复习之路每天一博客系列——TCP/IP协议栈(5)
前情回顾:一篇短短的博客明显不能满足TCP和UDP这两个饥渴的汉子,而且还被应用协议占了一小半的篇幅.在昨天结束之后,相信大家都基本对TCP/IP协议栈的轮廓有一个大概的印象了,能够对整体有所把握. ...
-
TCP/IP 协议栈
TCP(传输控制协议) 传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的.可靠的.基于字节流的传输层通信协议,由IETF的RFC 793定义. 在因特 ...
-
计算机网络基础之TCP/IP 协议栈
计算机网络基础之TCP/IP 协议栈 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.TCP/IP 协议栈概述 1>.什么是TCP/IP协议栈 Transmission C ...
-
TCP/IP 协议栈4层结构及3次握手4次挥手
TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输.TCP/IP 协议采用4层结构,分别是应用层.传输层.网络层和链路 ...
-
【转载】TCP/IP协议栈
TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输.TCP/IP 协议采用4层结构,分别是应用层.传输层.网络层和链路 ...
-
TCP/IP协议栈在Linux内核中的运行时序分析
网络程序设计调研报告 TCP/IP协议栈在Linux内核中的运行时序分析 姓名:柴浩宇 学号:SA20225105 班级:软设1班 2021年1月 调研要求 在深入理解Linux内核任务调度(中断处理 ...
随机推荐
-
phoenix将hdfs数据导入hbase
http://phoenix.apache.org/bulk_dataload.html
-
博客打开慢?请禁用WordPress默认的谷歌字体!
最近几天,谷歌中国挂了之后,发现我的博客打开极慢,原以为是空间问题,可一查,发现同台服务器的用户打开并不慢,排除了空间问题后,这边查询元素发现博客打开时加载了一个链接地址“fonts.googleap ...
-
Java自制人机小游戏——————————剪刀、石头、布
package com.hello.test; import java.util.Scanner; public class TestGame { public static void main(St ...
-
Python【基础第四篇】
一.迭代器(iterator) 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退. ...
-
SDUT1479数据结构实验之栈:行编辑器
先是普通的数组做法 #include<stdio.h> #include<string.h> int main() { ] ; while(~scanf("%s&qu ...
-
PHP 获取文件权限函数
/* * substr 返回字符串的子串 * base_convert 在任意进制之间转换数字 * fileperms 取得文件的权限 */ // 获取权限 function getChmod($fi ...
-
【HDOJ】4305 Lightning
1. 题目描述当一个结点lightning后,可以向其周围距离小于等于R的结点传播lightning.然后以该结点为中心继续传播.以此类推,问最终形成的树形结构有多少个. 2. 基本思路生成树级数模板 ...
-
[Effective Java读书笔记] 第二章 创建和销毁对象(1~7)
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3537576.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
-
USACO 1.3 Ski Course Design
Ski Course Design Farmer John has N hills on his farm (1 <= N <= 1,000), each with an integer ...
-
oralce 查看是否启动 登陆 创建用户 常用命令小记
最简单看进程有没有: ps -ef | grep ora 其次用oracle的的命令查看,比如: su - oracle sqlplus / as sysdba 看能连进数据库不. 创建用户和表空间: ...