UDP是用户数据报协议(User Datagram Protocol,UDP)的简称,其主要作用是将网络数据流量压缩成数据报形式,提供面向事务的简单信息传送服务。与TCP协议不同,UDP协议直接利用IP协议进行UDP数据报的传输,UDP提供的是面向无连接的、不可靠的数据报投递服务。当使用UDP协议传输信息时,用户应用程序必须负责解决数据报丢失、重复、排序,差错确认等问题。由于UDP具有资源消耗小、处理速度快的优点,所以通常视频、音频等可靠性要求不高的数据传输一般会使用UDP,即便有一定的丢包率,也不会对功能造成严重的影响。

UDP协议简介

UDP是无连接的,通信双方不需要建立物理链路连接。在网络中它用于处理数据包,在OSI模型中,它处于第四层传输层,即位于IP协议的上一层。它不对数据报分组、组装、校验和排序,因此是不可靠的。报文的发送者不知道报文是否被对方正确接收。

UDP数据报格式有首部和数据两个部分,首部很简单,为8个字节,包括以下部分:

(1)源端口:源端口号,2个字节,最大值为65535;

(2)目的端口:目的端口号,2个字节,最大值为65535;

(3)长度:2字节,UDP用户数据报的总长度;

(4)校验和:2字节,用于校验UDP数据报的数字段和包含UDP数据报首部的“伪首部”。其校验方法类似于IP分组首部中的首部校验和。

伪首部,又称为伪包头(Pseudo Header):是指在TCP的分段或UDP的数据报格式中,在数据报首部前面增加源IP地址、目的IP地址、IP分组的协议字段、TCP或UDP数据报的总长度等,共12字节,所构成的扩展首部结构。此伪首部是一个临时的结构,它既不向上也不向下传递,仅仅是为了保证可以校验套接字的正确性。

UDP协议数据报格式示意图如图:

UDP协议的特点如下。

(1)UDP传送数据前并不与对方建立连接,即UDP是无连接的。在传输数据前,发送方和接收方相互交换信息使双方同步;

(2)UDP对接收到的数据报不发送确认信号,发送端不知道数据是否被正确接收,也不会重发数据;

(3)UDP传送数据比TCP快速,系统开销也少:UDP比较简单,UDP头包含了源端口、目的端口、消息长度和校验和等很少的字节。由于UDP比TCP简单、灵活,常用于可靠性要求不高的数据传输,如视频、图片以及简单文件传输系统(TFTP)等。TCP则适用于可靠性要求很高但实时性要求不高的应用,如文件传输协议FTP、超文本传输协议HTTP、简单邮件传输协议SMTP等。

服务端开发

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel; public class ChineseProverbServer {
public void run(int port) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
//由于使用UDP通信,在创建Channel的时候需要通过NioDatagramChannel来创建
b.group(group).channel(NioDatagramChannel.class)
//随后设置Socket参数支持广播,
.option(ChannelOption.SO_BROADCAST, true)
//最后设置业务处理handler。
//相比于TCP通信,UDP不存在客户端和服务端的实际连接,
//因此不需要为连接(ChannelPipeline)设置handler,
//对于服务端,只需要设置启动辅助类的handler即可。
.handler(new ChineseProverbServerHandler());
b.bind(port).sync().channel().closeFuture().await();
} finally {
group.shutdownGracefully();
}
} public static void main(String[] args) throws Exception {
int port = 8080;
if (args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
new ChineseProverbServer().run(port);
}
} import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.ThreadLocalRandom; public class ChineseProverbServerHandler extends SimpleChannelInboundHandler {
// 谚语列表
private static final String[] DICTIONARY = {"只要功夫深,铁棒磨成针。",
"旧时王谢堂前燕,飞入寻常百姓家。", "洛阳亲友如相问,一片冰心在玉壶。", "一寸光阴一寸金,寸金难买寸光阴。",
"老骥伏枥,志在千里。烈士暮年,壮心不已!"}; private String nextQuote() {
//由于ChineseProverbServerHandler存在多线程并发操作的可能,
//所以使用了Netty的线程安全随机类ThreadLocalRandom。
// 如果使用的是JDK7,可以直接使用JDK7的java.util.concurrent.ThreadLocalRandom。
int quoteId = ThreadLocalRandom.current().nextInt(DICTIONARY.length);
return DICTIONARY[quoteId];
} @Override
public void messageReceived(ChannelHandlerContext ctx, Object msg)throws Exception {
//Netty对UDP进行了封装,因此,接收到的是Netty封装后的io.netty. channel.socket.DatagramPacket对象。
DatagramPacket packet = (DatagramPacket) msg;
//将packet内容转换为字符串(利用ByteBuf的toString(Charset)方法),
String req = packet.content().toString(CharsetUtil.UTF_8);
System.out.println(req);
// 然后对请求消息进行合法性判断:如果是“谚语字典查询?”,则构造应答消息返回。
// DatagramPacket有两个参数:第一个是需要发送的内容,为ByteBuf;
// 另一个是目的地址,包括IP和端口,可以直接从发送的报文DatagramPacket中获取。
if ("谚语字典查询?".equals(req)) {
ctx.writeAndFlush(
new DatagramPacket(Unpooled.copiedBuffer("谚语查询结果: " + nextQuote(), CharsetUtil.UTF_8),
packet.sender()));
}
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
ctx.close();
cause.printStackTrace();
}
}

客户端开发

UDP程序的客户端和服务端代码非常相似,唯一不同之处是UDP客户端会主动构造请求消息,向本网段内的所有主机广播请求消息,对于服务端而言,接收到广播请求消息之后会向广播消息的发起方进行定点发送。

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil; import java.net.InetSocketAddress; public class ChineseProverbClient { public void run(int port) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
//创建UDP Channel和设置支持广播属性等与服务端完全一致。
// 由于不需要和服务端建立链路,UDP Channel创建完成之后,客户端就要主动发送广播消息;
// TCP客户端是在客户端和服务端链路建立成功之后由客户端的业务handler发送消息,这就是两者最大的区别。
b.group(group).channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new ChineseProverbClientHandler());
Channel ch = b.bind(0).sync().channel();
// 向网段内的所有机器广播UDP消息
// 用于构造DatagramPacket发送广播消息,
// 注意,广播消息的IP设置为“255.255.255.255”。
// 消息广播之后,客户端等待15s用于接收服务端的应答消息,然后退出并释放资源。
ch.writeAndFlush(
new DatagramPacket(Unpooled.copiedBuffer("谚语字典查询?",CharsetUtil.UTF_8),
new InetSocketAddress("255.255.255.255", port))
).sync();
if (!ch.closeFuture().await(15000)) {
System.out.println("查询超时!");
}
} finally {
group.shutdownGracefully();
}
} public static void main(String[] args) throws Exception {
int port = 8080;
if (args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
new ChineseProverbClient().run(port);
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil; public class ChineseProverbClientHandler extends SimpleChannelInboundHandler { @Override
public void messageReceived(ChannelHandlerContext ctx, Object o)
throws Exception {
//接收到服务端的消息之后将其转成字符串,然后判断是否以“谚语查询结果:”开头,
//如果没有发生丢包等问题,数据是完整的,就打印查询结果,然后释放资源。
DatagramPacket msg = (DatagramPacket)o;
String response = msg.content().toString(CharsetUtil.UTF_8);
if (response.startsWith("谚语查询结果:")) {
System.out.println(response);
ctx.close();
}
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}

UDP协议开发的更多相关文章

  1. 【Java】学习路径54-使用UDP协议开发发送、接收端

    UDP协议,简单的说就是,发信息. 不管对方有没有收到. 发送端: import java.net.*; public class UDP_Send { public static void main ...

  2. python 全栈开发,Day33(tcp协议和udp协议,互联网协议与osi模型,socket概念,套接字(socket)初使用)

    先来回顾一下昨天的内容 网络编程开发架构 B/S C/S架构网卡 mac地址网段 ip地址 : 表示了一台电脑在网络中的位置 子网掩码 : ip和子网掩码按位与得到网段 网关ip : 内置在路由器中的 ...

  3. Java开发笔记(一百一十六)采用UDP协议的Socket通信

    前面介绍了如何通过Socket接口传输文本与文件,在示例代码中,Socket客户端得先调用connect方法连接服务端,确认双方成功连上后才能继续运行后面的代码,这种确认机制确保客户端与服务端的的确确 ...

  4. 软件开发架构,网络编程简介,OSI七层协议,TCP和UDP协议

    软件开发架构 什么是软件开发架构 1.软件架构是一个系统的草图. 2.软件架构描述的对象是直接构成系统的抽象组件. 3.各个组件之间的连接则明确和相对细致地描述组件之间的通讯. 4.在实现阶段,这些抽 ...

  5. python 全栈开发,Day34(基于UDP协议的socket)

    昨日内容回顾 网络的基础概念arp协议 :通过ip地址找到mac地址五层模型 : 应用层 传输层 网络层 数据链路层 物理层tcp协议 : 可靠的 面向连接 全双工 三次握手 四次挥手udp协议 : ...

  6. TCP协议与UDP协议的区别

    TCP协议与UDP协议的区别(转) 首先咱们弄清楚,TCP协议和UCP协议与TCP/IP协议的联系,很多人犯糊涂了,一直都是说TCP/IP协议与UDP协议的区别,我觉得这是没有从本质上弄清楚网络通信! ...

  7. 采用UDP协议的PIC32MZ ethernet bootloader

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 经过千辛万苦,今天终于 ...

  8. 采用UDP协议实现PIC18F97J60 ethernet bootloader

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). TCP/IP Stac ...

  9. [深入浅出WP8.1(Runtime)]Socket编程之UDP协议

    13.3 Socket编程之UDP协议 UDP协议和TCP协议都是Socket编程的协议,但是与TCP协议不同,UDP协议并不提供超时重传,出错重传等功能,也就是说其是不可靠的协议.UDP适用于一次只 ...

随机推荐

  1. 新手指南: Linux 新手应该知道的 26 个命令

    当你进入了 Linux 的世界,在下载.安装 了某个 Linux 发行版,体验了 Linux 桌面并安装了一些你喜爱和需要的软件之后,应该去了解下 Linux 真正的魅力所在:命令行.每一个 Linu ...

  2. iOS - YYAdd对UIDevice的拓展

    YYKit中对UIDevice的拓展,accumulate knowledge !!! 首先 #include <sys/socket.h> #include <sys/sysctl ...

  3. Simple Network Management Protocol - SNMP Tutorial

    30.9 Simple Network Management Protocol Network management protocols specify communication between t ...

  4. Samba服务器配置

    Samba服务器配置流程: (1)安装samba服务器先用#rpm -ivh samba-列出与samba有关的rpm包然后选择第一个包,用tab键补齐文件名 (2)创建新用户和其密码#useradd ...

  5. 图解c/c++多级指针与“多维”数组

    声明:本文为原创博文,如有转载,请注明出处.若本文有编辑错误.概念错误或者逻辑错误,请予以指正,谢谢. 指针与数组是C/C++编程中非常重要的元素,同时也是较难以理解的.其中,多级指针与“多维”数组更 ...

  6. sobel算子的一些细节

    1. 形式 Gy 上下颠倒的 (*A表示卷积图像,忽略先): 看得出来,sobel算子感觉并不统一,特别是方向,我们知道matlab的图像格式是,x轴从左到右,y轴从上到下,原点在左上角. 所以,第二 ...

  7. kettle参数、变量详细讲解[转]

    kettle 3.2 以前的版本里只有 variable 和 argument,kettle 3.2 中,又引入了 parameter 概念:variable 即environment variabl ...

  8. java ssh 框架下 利用junit4 spring-test进行单元测试

    ssh框架下  由于bean实列 都交给spring 管理,要做单元测试就比较苦难,junit4 引入注解方便很多: 1. 加入依赖包 使用Spring的测试框架需要加入以下依赖包: JUnit 4 ...

  9. C语言基础(1)-基本语法及注意事项

    1. include 头文件包含 #include <stdio.h>这个是hello world程序的第一句话 # 代表预编译指令 #include的意思就是头文件包含,使用C语言库函数 ...

  10. 【转载】借助GitHub托管你的项目代码

    PS:自己关注博客园有2年之久了,不久前才申请注册账号.GitHub也差不多一年多了,因英语水平刚刚及格,所以去GitHub没有博客园多,也是几个月前才注册了账号,前几天休息时看到 EdisonCho ...