中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在java中的使用UDP協議

發布時間:2021-02-19 14:28:33 來源:億速云 閱讀:178 作者:Leah 欄目:開發技術

本篇文章為大家展示了如何在java中的使用UDP協議,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

UDP是面向無連接的通訊協議,由于通訊不需要連接,所以可以實現廣播發送。UDP通訊時不需要接收方確認,屬于不可靠的傳輸,可能會出現丟包現象,實際應用中要求程序員編程驗證。

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

UDP報文格式如下:

如何在java中的使用UDP協議

UDP首部有8個字節,由4個字段構成,每個字段都是兩個字節,

  • 源端口:數據發送方的端口號.

  • 目的端口:數據接收方的端口號。

  • 長度:UDP數據報的整個長度(包括首部和數據),其最小值為8(只有首部)。

  • 校驗和:檢測UDP數據報在傳輸中是否有錯,有錯則丟棄。

可以使用nc發送UDP數據包:echo hello | nc -uv 127.0.0.1 9999

用tcpdump抓取到的數據包如下(注意先運行tcpdump,然后再執行nc命令):

# tcpdump -i lo -X udp port 9999
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
11:19:39.267912 IP localhost.45666 > localhost.distinct: UDP, length 6
	0x0000: 4500 0022 5914 4000 4011 e3b4 7f00 0001 E.."Y.@.@.......
	0x0010: 7f00 0001 b262 270f 000e fe21 6865 6c6c .....b'....!hell
	0x0020: 6f0a     o.
... ...

說明:

  1. 源端口:0xb262,十進制的45666。

  2. 目的端口:0x270f,十進制的9999。

  3. 長度:0x000e,14個字節的報文長度。

  4. 校驗和:0xfe21。

bio之單播

單播就是一對一通信。

服務器端代碼如下:

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()));
 }
}

客戶端和服務端的代碼幾乎一致,只不過接收和發送數據的順序不一致,receive和send都歐式阻塞方法。

bio之廣播

廣播:同一網段所有主機都能接收,前提是端口要開啟監聽。

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

DatagramPacket datagramPacket = new DatagramPacket(req, req.length, new InetSocketAddress("255.255.255.255", 9999));

bio之多播(組播)

多播數據報套接字類用于發送和接收IP多播包。MulticastSocket是一種DatagramSocket,它具有加入Internet上其他多播主機的“組”的附加功能。

多播組通過D類IP地址和標準UDP端口號指定。D類IP地址在224.0.0.0和239.255.255.255的范圍內。地址224.0.0.0被保留,不應使用。

可以通過首先使用所需端口創建MulticastSocket,然后調用joinGroup(InetAddress groupAddr)方法來加入多播組。

服務器端代碼如下:

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實現單播

服務器端代碼如下:

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實現單播

服務器端代碼如下:

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 {
    // 接收數據
    System.out.println(msg.content().toString(CharsetUtil.UTF_8));
    // 發送數據
    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 {
    // 接收數據
    System.out.println(msg.content().toString(CharsetUtil.UTF_8));
    ctx.close();
   }
   });

  Channel channel = bootstrap.bind(0).sync().channel();

  // 發送數據
  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("查詢超時");
  }
 } finally {
  group.shutdownGracefully();
 }

 }
}

Netty實現廣播

只需要將netty實現的單播的客戶端代碼做如下修改:

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)));

底層實現

recvfrom負責接收UDP數據,其函數聲明如下:

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

sendto負責發送UDP數據,其函數聲明如下:

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

下面通過對bio之單播的例子所產生的系統調用進行跟蹤:

啟動服務器端服務Server:

# strace -ff -o out java Server

然后使用nc命令充當客戶端進行連接:echo hello | nc -uv 127.0.0.1 9999

產生的系統調用中關鍵信息如下:

socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 4
bind(4, {sa_family=AF_INET6, sin6_port=htons(9999), inet_pton(AF_INET6, "::", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 28) = 0
recvfrom(4, "hello\n", 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]) = 6
write(1, "receive from client: hello\n\0\0\0\0\0"..., 1045) = 1045
write(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

可見發送和接收數據確實使用了上面的系統調用,另外上面的系統調用中并沒有listen函數,不需要監聽端口,再次驗證UDP是面向無連接的。

上述內容就是如何在java中的使用UDP協議,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

罗甸县| 建始县| 河曲县| 东海县| 阜阳市| 永州市| 苏尼特右旗| 托里县| 郎溪县| 定西市| 弥勒县| 页游| 康平县| 于都县| 运城市| 淅川县| 威远县| 房产| 黑水县| 墨脱县| 鹿邑县| 双城市| 绵竹市| 台中县| 上高县| 湘阴县| 绥阳县| 赤水市| 新邵县| 乌鲁木齐市| 揭西县| 边坝县| 镇赉县| 定南县| 湖州市| 章丘市| 徐汇区| 大名县| 八宿县| 博兴县| 九江市|