UDP协议开发
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协议开发的更多相关文章
- 【Java】学习路径54-使用UDP协议开发发送、接收端
UDP协议,简单的说就是,发信息. 不管对方有没有收到. 发送端: import java.net.*; public class UDP_Send { public static void main ...
- python 全栈开发,Day33(tcp协议和udp协议,互联网协议与osi模型,socket概念,套接字(socket)初使用)
先来回顾一下昨天的内容 网络编程开发架构 B/S C/S架构网卡 mac地址网段 ip地址 : 表示了一台电脑在网络中的位置 子网掩码 : ip和子网掩码按位与得到网段 网关ip : 内置在路由器中的 ...
- Java开发笔记(一百一十六)采用UDP协议的Socket通信
前面介绍了如何通过Socket接口传输文本与文件,在示例代码中,Socket客户端得先调用connect方法连接服务端,确认双方成功连上后才能继续运行后面的代码,这种确认机制确保客户端与服务端的的确确 ...
- 软件开发架构,网络编程简介,OSI七层协议,TCP和UDP协议
软件开发架构 什么是软件开发架构 1.软件架构是一个系统的草图. 2.软件架构描述的对象是直接构成系统的抽象组件. 3.各个组件之间的连接则明确和相对细致地描述组件之间的通讯. 4.在实现阶段,这些抽 ...
- python 全栈开发,Day34(基于UDP协议的socket)
昨日内容回顾 网络的基础概念arp协议 :通过ip地址找到mac地址五层模型 : 应用层 传输层 网络层 数据链路层 物理层tcp协议 : 可靠的 面向连接 全双工 三次握手 四次挥手udp协议 : ...
- TCP协议与UDP协议的区别
TCP协议与UDP协议的区别(转) 首先咱们弄清楚,TCP协议和UCP协议与TCP/IP协议的联系,很多人犯糊涂了,一直都是说TCP/IP协议与UDP协议的区别,我觉得这是没有从本质上弄清楚网络通信! ...
- 采用UDP协议的PIC32MZ ethernet bootloader
了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 经过千辛万苦,今天终于 ...
- 采用UDP协议实现PIC18F97J60 ethernet bootloader
了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). TCP/IP Stac ...
- [深入浅出WP8.1(Runtime)]Socket编程之UDP协议
13.3 Socket编程之UDP协议 UDP协议和TCP协议都是Socket编程的协议,但是与TCP协议不同,UDP协议并不提供超时重传,出错重传等功能,也就是说其是不可靠的协议.UDP适用于一次只 ...
随机推荐
- AI贪吃蛇(二)
前言 之前写过一篇关于贪吃蛇AI的博客,当时虽然取得了一些成果,但是也存在许多问题,所以最近又花了三天时间重新思考了一下.以下是之前博客存在的一些问题: 策略不对,只要存在找不到尾巴的情况就可能失败, ...
- RabbitMQ 声明Queue时的参数们的Power
参数们的Power 在声明队列的时候会有很多的参数 public static QueueDeclareOk QueueDeclare(this IModel model, string queue ...
- 怪物AI之发现玩家(视觉范围发现系列)
在网上找到一些资料参考,然后写写自己的想法. 这里感谢MOMO等大神. 我们用玩家检测怪物的方法来测,这样比较试用与弱联网游戏,每次在同步玩家的时候来判断玩家与怪物的位置. 这里给出两个处理方式: 1 ...
- Long Short-Term Memory (LSTM)公式简介
Long short-term memory: make that short-term memory last for a long time. Paper Reference: A Critica ...
- easyUi datagrid 返回时间格式化操作
1.格式化返回的时间 { field : 'endTime', title : '轮播图片循环的结束时间', width : 50, align : 'center' //格式化时间操作 format ...
- 关于背景图相对父容器垂直居中问题 —— vertical-align 和 line-height 之间的区别
html css <div class="register-wrapper"> <div class="register"> &l ...
- .Net 中的反射(动态创建类型实例) - Part.4
动态创建对象 在前面节中,我们先了解了反射,然后利用反射查看了类型信息,并学习了如何创建自定义特性,并利用反射来遍历它.可以说,前面三节,我们学习的都是反射是什么,在接下来的章节中,我们将学习反射可以 ...
- 基于canvas的陈列订货的分析
订货会软件中又新增了进行陈列订货,即一杆衣服订的显示出来,没订的不显示出来 主要遇到的问题是如何呈现,原先老是想着定位,left,top但是花出来的图容易出现原先的数据填写错误导致后期的图片的呈现出现 ...
- zendstudio快捷键收录
360截屏快捷键:ctrl+shift+x zendstudio:注释代码:ctrl+shift+/ 删除光标所在行:ctrl+D 复制当前行:ctrl+alt+↓ 上下行互换:alt+↑/↓ 代码格 ...
- 大熊君学习html5系列之------History API(SPA单页应用的必备------重构完结版)
一,开篇分析 Hi,大家好!大熊君又和大家见面了,(*^__^*) 嘻嘻……,这系列文章主要是学习Html5相关的知识点,以学习API知识点为入口,由浅入深的引入实例, 让大家一步一步的体会" ...