色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

詳解UDP協(xié)議格式及在java中的使用

瀏覽:163日期:2022-08-16 16:12:04

UDP是面向無(wú)連接的通訊協(xié)議,由于通訊不需要連接,所以可以實(shí)現(xiàn)廣播發(fā)送。UDP通訊時(shí)不需要接收方確認(rèn),屬于不可靠的傳輸,可能會(huì)出現(xiàn)丟包現(xiàn)象,實(shí)際應(yīng)用中要求程序員編程驗(yàn)證。

UDP適用于DNS、視頻音頻等多媒體通信、廣播通信(廣播、多播)。例如我們常用的QQ,就是一個(gè)以UDP為主,TCP為輔的通訊協(xié)議。

UDP報(bào)文格式如下:

詳解UDP協(xié)議格式及在java中的使用

UDP首部有8個(gè)字節(jié),由4個(gè)字段構(gòu)成,每個(gè)字段都是兩個(gè)字節(jié),

源端口:數(shù)據(jù)發(fā)送方的端口號(hào). 目的端口:數(shù)據(jù)接收方的端口號(hào)。 長(zhǎng)度:UDP數(shù)據(jù)報(bào)的整個(gè)長(zhǎng)度(包括首部和數(shù)據(jù)),其最小值為8(只有首部)。 校驗(yàn)和:檢測(cè)UDP數(shù)據(jù)報(bào)在傳輸中是否有錯(cuò),有錯(cuò)則丟棄。

可以使用nc發(fā)送UDP數(shù)據(jù)包:echo hello | nc -uv 127.0.0.1 9999。

用tcpdump抓取到的數(shù)據(jù)包如下(注意先運(yùn)行tcpdump,然后再執(zhí)行nc命令):

# tcpdump -i lo -X udp port 9999tcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes11:19:39.267912 IP localhost.45666 > localhost.distinct: UDP, length 60x0000: 4500 0022 5914 4000 4011 e3b4 7f00 0001 E..'Y.@[email protected]: 7f00 0001 b262 270f 000e fe21 6865 6c6c .....b’....!hell0x0020: 6f0a o.... ...

說(shuō)明:

源端口:0xb262,十進(jìn)制的45666。 目的端口:0x270f,十進(jìn)制的9999。 長(zhǎng)度:0x000e,14個(gè)字節(jié)的報(bào)文長(zhǎng)度。 校驗(yàn)和:0xfe21。bio之單播

單播就是一對(duì)一通信。

服務(wù)器端代碼如下:

package com.morris.udp.bio.single;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;public class Server { public static void main(String[] args) throws IOException { DatagramSocket datagramSocket = new DatagramSocket(9999); byte[] bytes = new byte[1024]; DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length); datagramSocket.receive(datagramPacket); System.out.println('receive from client: ' + new String(bytes)); byte[] req = 'hello client'.getBytes(); DatagramPacket resp = new DatagramPacket(req, req.length, datagramPacket.getSocketAddress()); datagramSocket.send(resp); }}

客戶端代碼如下:

package com.morris.udp.bio.single;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetSocketAddress;public class Client { public static void main(String[] args) throws IOException { DatagramSocket datagramSocket = new DatagramSocket(); byte[] req = 'hello server'.getBytes(); DatagramPacket datagramPacket = new DatagramPacket(req, req.length, new InetSocketAddress('127.0.0.1', 9999)); datagramSocket.send(datagramPacket); datagramSocket.receive(datagramPacket); System.out.println('receive from server: ' + new String(datagramPacket.getData())); }}

客戶端和服務(wù)端的代碼幾乎一致,只不過(guò)接收和發(fā)送數(shù)據(jù)的順序不一致,receive和send都?xì)W式阻塞方法。

bio之廣播

廣播:同一網(wǎng)段所有主機(jī)都能接收,前提是端口要開(kāi)啟監(jiān)聽(tīng)。

只需要將單播的例子中客戶端發(fā)送數(shù)據(jù)的IP修改為255.255.255.255即可,具體修改如下:

DatagramPacket datagramPacket = new DatagramPacket(req, req.length, new InetSocketAddress('255.255.255.255', 9999));bio之多播(組播)

多播數(shù)據(jù)報(bào)套接字類用于發(fā)送和接收IP多播包。MulticastSocket是一種DatagramSocket,它具有加入Internet上其他多播主機(jī)的“組”的附加功能。

多播組通過(guò)D類IP地址和標(biāo)準(zhǔn)UDP端口號(hào)指定。D類IP地址在224.0.0.0和239.255.255.255的范圍內(nèi)。地址224.0.0.0被保留,不應(yīng)使用。

可以通過(guò)首先使用所需端口創(chuàng)建MulticastSocket,然后調(diào)用joinGroup(InetAddress groupAddr)方法來(lái)加入多播組。

服務(wù)器端代碼如下:

package com.morris.udp.bio.multicast;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.MulticastSocket;public class Server { public static void main(String[] args) throws IOException { InetAddress group = InetAddress.getByName('228.5.6.7'); MulticastSocket s = new MulticastSocket(6789); s.joinGroup(group); byte[] buf = new byte[1000]; DatagramPacket recv = new DatagramPacket(buf, buf.length); s.receive(recv); System.out.println('receive : ' + new String(buf)); s.leaveGroup(group); }}

客戶端代碼如下:

package com.morris.udp.bio.multicast;import java.io.IOException;import java.net.*;public class Client { public static void main(String[] args) throws IOException { String msg = 'Hello'; InetAddress group = InetAddress.getByName('228.5.6.7'); MulticastSocket s = new MulticastSocket(); s.joinGroup(group); DatagramPacket hi = new DatagramPacket(msg.getBytes(), msg.length(), group, 6789); s.send(hi); s.leaveGroup(group); }}NIO實(shí)現(xiàn)單播

服務(wù)器端代碼如下:

package com.morris.udp.nio;import java.io.IOException;import java.net.InetSocketAddress;import java.net.SocketAddress;import java.nio.ByteBuffer;import java.nio.channels.DatagramChannel;public class Server { public static void main(String[] args) throws IOException { DatagramChannel datagramChannel = DatagramChannel.open(); datagramChannel.bind(new InetSocketAddress(9999)); // datagramChannel.configureBlocking(false); ByteBuffer byteBuffer = ByteBuffer.allocate(128); SocketAddress receive = datagramChannel.receive(byteBuffer); byteBuffer.flip(); byte[] bytes = new byte[byteBuffer.remaining()]; byteBuffer.get(bytes); System.out.println('receive from client: ' + new String(bytes)); byteBuffer.clear(); byteBuffer.put('hello client'.getBytes()); datagramChannel.send(byteBuffer, receive); }}

客戶端代碼如下:

package com.morris.udp.nio;import java.io.IOException;import java.net.InetSocketAddress;import java.net.SocketAddress;import java.nio.ByteBuffer;import java.nio.channels.DatagramChannel;public class Client { public static void main(String[] args) throws IOException { DatagramChannel datagramChannel = DatagramChannel.open(); // datagramChannel.configureBlocking(false); String req = 'hello server'; ByteBuffer byteBuffer = ByteBuffer.allocate(req.length()); byteBuffer.put(req.getBytes()); byteBuffer.flip(); datagramChannel.send(byteBuffer, new InetSocketAddress('127.0.0.1', 9999)); datagramChannel.receive(byteBuffer); byteBuffer.flip(); byte[] bytes = new byte[byteBuffer.remaining()]; byteBuffer.get(bytes); System.out.println('receive from server: ' + new String(bytes)); }}Netty實(shí)現(xiàn)單播

服務(wù)器端代碼如下:

package com.morris.udp.netty.single;import io.netty.bootstrap.Bootstrap;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelOption;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.DatagramPacket;import io.netty.channel.socket.nio.NioDatagramChannel;import io.netty.util.CharsetUtil;public class Server { private static final int port = 8899; public static void main(String[] args) throws InterruptedException { NioEventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).channel(NioDatagramChannel.class) .handler(new SimpleChannelInboundHandler<DatagramPacket>() { @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { // 接收數(shù)據(jù) System.out.println(msg.content().toString(CharsetUtil.UTF_8)); // 發(fā)送數(shù)據(jù) ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer('hello client', CharsetUtil.UTF_8), msg.sender())); ctx.close(); } }); bootstrap.bind(port).sync().channel().closeFuture().await(); } finally { group.shutdownGracefully(); } }}

客戶端代碼如下:

package com.morris.udp.netty.single;import io.netty.bootstrap.Bootstrap;import io.netty.buffer.Unpooled;import io.netty.channel.Channel;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelOption;import io.netty.channel.SimpleChannelInboundHandler;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 Client { public static void main(String[] args) throws InterruptedException { NioEventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).channel(NioDatagramChannel.class) .handler(new SimpleChannelInboundHandler<DatagramPacket>() { @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { // 接收數(shù)據(jù) System.out.println(msg.content().toString(CharsetUtil.UTF_8)); ctx.close(); } }); Channel channel = bootstrap.bind(0).sync().channel(); // 發(fā)送數(shù)據(jù) channel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer('hello server', CharsetUtil.UTF_8), new InetSocketAddress('127.0.0.1', 8899))); if (!channel.closeFuture().await(30 * 1000)) { System.err.println('查詢超時(shí)'); } } finally { group.shutdownGracefully(); } }}Netty實(shí)現(xiàn)廣播

只需要將netty實(shí)現(xiàn)的單播的客戶端代碼做如下修改:

1.增加option:

.option(ChannelOption.SO_BROADCAST, true)

2.將IP地址修改為廣播地址255.255.255.255:

channel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer('hello server', CharsetUtil.UTF_8), new InetSocketAddress('255.255.255.255', 8899)));底層實(shí)現(xiàn)

recvfrom負(fù)責(zé)接收UDP數(shù)據(jù),其函數(shù)聲明如下:

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

sendto負(fù)責(zé)發(fā)送UDP數(shù)據(jù),其函數(shù)聲明如下:

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

下面通過(guò)對(duì)bio之單播的例子所產(chǎn)生的系統(tǒng)調(diào)用進(jìn)行跟蹤:

啟動(dòng)服務(wù)器端服務(wù)Server:

# strace -ff -o out java Server

然后使用nc命令充當(dāng)客戶端進(jìn)行連接:echo hello | nc -uv 127.0.0.1 9999。

產(chǎn)生的系統(tǒng)調(diào)用中關(guān)鍵信息如下:

socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 4bind(4, {sa_family=AF_INET6, sin6_port=htons(9999), inet_pton(AF_INET6, '::', &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 28) = 0recvfrom(4, 'hellon', 1024, 0, {sa_family=AF_INET6, sin6_port=htons(7361), inet_pton(AF_INET6, '::ffff:127.0.0.1', &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, [28]) = 6write(1, 'receive from client: hellon00000'..., 1045) = 1045write(1, 'n', 1) sendto(4, 'hello client', 12, 0, {sa_family=AF_INET6, sin6_port=htons(7361), inet_pton(AF_INET6, '::ffff:127.0.0.1', &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 28) = 12

可見(jiàn)發(fā)送和接收數(shù)據(jù)確實(shí)使用了上面的系統(tǒng)調(diào)用,另外上面的系統(tǒng)調(diào)用中并沒(méi)有l(wèi)isten函數(shù),不需要監(jiān)聽(tīng)端口,再次驗(yàn)證UDP是面向無(wú)連接的。

到此這篇關(guān)于詳解UDP協(xié)議格式及在java中的使用的文章就介紹到這了,更多相關(guān)java中使用UDP協(xié)議內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 国产美女白丝袜精品_a不卡 | 欧美日韩永久久一区二区三区 | 亚洲国产欧美国产综合一区 | 毛片在线全部免费观看 | 成人a免费α片在线视频网站 | 福利视频午夜 | 亚洲成人tv | 国产呦精品一区二区三区网站 | 怡红院免费全部视频在线视频 | 狠狠88综合久久久久综合网 | 国产精品亚洲精品爽爽 | 在线观看视频中文字幕 | 久久综合久久久 | 高清一区二区三区四区五区 | 日本特黄特色大片免费视频网站 | 国产女人在线观看 | 国产精品二区在线 | 高清在线一区二区 | a毛片全部播放免费视频完整18 | 毛片视频网址 | 国产视频中文字幕 | 欧美在线观看不卡 | 亚洲免费区 | 欧美视频一区在线观看 | 91久久国产综合精品 | 免看一级a毛片一片成人不卡 | 一级美女视频 | 欧美日韩国产高清一区二区三区 | 久久视精品 | 天堂中文资源在线8 | 毛片网站观看 | 午夜香蕉成视频人网站高清版 | 精品精品国产自在久久高清 | 高清午夜毛片 | 日韩精品一区二区三区 在线观看 | 日韩高清一级毛片 | 欧美成人怡红院在线观看 | 毛片在线不卡 | 怡红院精品视频 | 成人欧美一区二区三区在线观看 | 波多野结衣一区二区三区在线观看 |