最近接到一个关于写UDP服务器的任务,然后去netty官网下载了netty的jar包(netty-4.0.49.Final.tar.bz2),解压后,可以看到上面有不少example,找到其中的关于UDP的例子。
在此学习。
直接上栗子:
服务端:QuoteOfTheMomentServer.java(其中的代码稍微有点修改,测试了下redis,需要的同学可以直接把jar包中的栗子拷贝下来即可)
1 package com.wj.test; 2 3 import org.slf4j.Logger; 4 import org.slf4j.LoggerFactory; 5 6 import io.netty.bootstrap.Bootstrap; 7 import io.netty.channel.ChannelOption; 8 import io.netty.channel.EventLoopGroup; 9 import io.netty.channel.nio.NioEventLoopGroup; 10 import io.netty.channel.socket.nio.NioDatagramChannel; 11 12 /** 13 * A UDP server that responds to the QOTM (quote of the moment) request to a {@link QuoteOfTheMomentClient}. 14 * 15 * Inspired by <a href="http://docs.oracle.com/javase/tutorial/networking/datagrams/clientServer.html">the official 16 * Java tutorial</a>. 17 */ 18 public final class QuoteOfTheMomentServer { 19 20 private static final int PORT = Integer.parseInt(System.getProperty("port", "8889")); 21 22 private static final Logger log=LoggerFactory.getLogger(QuoteOfTheMomentServer.class); 23 24 public static void main(String[] args) throws Exception { 25 EventLoopGroup group = new NioEventLoopGroup(); 26 log.info("QuoteOfTheMomentServer" + " + start"); 27 try { 28 Bootstrap b = new Bootstrap(); 29 b.group(group) 30 .channel(NioDatagramChannel.class) 31 .option(ChannelOption.SO_BROADCAST, true) 32 .handler(new QuoteOfTheMomentServerHandler()); 33 34 b.bind(PORT).sync().channel().closeFuture().await(); 35 } finally { 36 group.shutdownGracefully(); 37 } 38 } 39 }
1 /* 2 * Copyright 2012 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with the License. You may obtain a copy of the License at: 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package com.wj.test; 17 18 import io.netty.buffer.Unpooled; 19 import io.netty.channel.ChannelHandlerContext; 20 import io.netty.channel.SimpleChannelInboundHandler; 21 import io.netty.channel.socket.DatagramPacket; 22 import io.netty.util.CharsetUtil; 23 import redis.clients.jedis.Jedis; 24 25 import java.util.Random; 26 import org.slf4j.Logger; 27 import org.slf4j.LoggerFactory; 28 29 import com.wj.test.redis.RedisUtil; 30 31 32 33 public class QuoteOfTheMomentServerHandler extends SimpleChannelInboundHandler<DatagramPacket> { 34 35 private static final Logger log=LoggerFactory.getLogger(QuoteOfTheMomentServerHandler.class); 36 37 private static final Random random = new Random(); 38 39 // Quotes from Mohandas K. Gandhi: 40 private static final String[] quotes = { 41 "Where there is love there is life.", 42 "First they ignore you, then they laugh at you, then they fight you, then you win.", 43 "Be the change you want to see in the world.", 44 "The weak can never forgive. Forgiveness is the attribute of the strong.", 45 }; 46 47 private static String nextQuote() { 48 int quoteId; 49 synchronized (random) { 50 quoteId = random.nextInt(quotes.length); 51 } 52 return quotes[quoteId]; 53 } 54 55 @Override 56 public void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { 57 System.err.println(packet); 58 59 60 61 if (packet.content().toString(CharsetUtil.UTF_8) != null ) { 62 63 System.out.println(packet.content().toString(CharsetUtil.UTF_8)); 64 System.out.println(packet.sender()); 65 66 Jedis jedisK = RedisUtil.getJedis(); 67 jedisK.select(1); 68 jedisK.lpush("test:udp:msg", packet.content().toString(CharsetUtil.UTF_8)); 69 70 71 72 ctx.write(new DatagramPacket( 73 // Unpooled.copiedBuffer("QOTM: " + nextQuote(), CharsetUtil.UTF_8), packet.sender())); 74 Unpooled.copiedBuffer("QOTM: " + "sometest", CharsetUtil.UTF_8), packet.sender())); 75 }else { 76 log.info("Exception"); 77 } 78 } 79 80 @Override 81 public void channelReadComplete(ChannelHandlerContext ctx) { 82 ctx.flush(); 83 } 84 85 @Override 86 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 87 cause.printStackTrace(); 88 // We don't close the channel because we can keep serving requests. 89 } 90 }
客户端:QuoteOfTheMomentClient.java
1 /* 2 * Copyright 2012 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with the License. You may obtain a copy of the License at: 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package com.wj.test; 17 18 import io.netty.bootstrap.Bootstrap; 19 import io.netty.buffer.Unpooled; 20 import io.netty.channel.Channel; 21 import io.netty.channel.ChannelOption; 22 import io.netty.channel.EventLoopGroup; 23 import io.netty.channel.nio.NioEventLoopGroup; 24 import io.netty.channel.socket.DatagramPacket; 25 import io.netty.channel.socket.nio.NioDatagramChannel; 26 import io.netty.util.CharsetUtil; 27 import io.netty.util.internal.SocketUtils; 28 29 /** 30 * A UDP broadcast client that asks for a quote of the moment (QOTM) to {@link QuoteOfTheMomentServer}. 31 * 32 * Inspired by <a href="http://docs.oracle.com/javase/tutorial/networking/datagrams/clientServer.html">the official 33 * Java tutorial</a>. 34 */ 35 public final class QuoteOfTheMomentClient { 36 37 static final int PORT = Integer.parseInt(System.getProperty("port", "8889")); 38 39 public static void main(String[] args) throws Exception { 40 41 EventLoopGroup group = new NioEventLoopGroup(); 42 try { 43 Bootstrap b = new Bootstrap(); 44 b.group(group) 45 .channel(NioDatagramChannel.class) 46 .option(ChannelOption.SO_BROADCAST, true) 47 .handler(new QuoteOfTheMomentClientHandler()); 48 49 Channel ch = b.bind(0).sync().channel(); 50 51 // Broadcast the QOTM request to port 8080. 52 String str = "38567071 13801783144 18917565379 20170621183115 20170621183118 05"; 53 ch.writeAndFlush(new DatagramPacket( 54 Unpooled.copiedBuffer(str, CharsetUtil.UTF_8), 55 SocketUtils.socketAddress("localhost", PORT))).sync(); 56 57 // QuoteOfTheMomentClientHandler will close the DatagramChannel when a 58 // response is received. If the channel is not closed within 5 seconds, 59 // print an error message and quit. 60 if (!ch.closeFuture().await(5000)) { 61 System.err.println("QOTM request timed out."); 62 } 63 } finally { 64 group.shutdownGracefully(); 65 } 66 } 67 }
1 package com.wj.test; 2 3 /* 4 * Copyright 2012 The Netty Project 5 * 6 * The Netty Project licenses this file to you under the Apache License, 7 * version 2.0 (the "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at: 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 * License for the specific language governing permissions and limitations 16 * under the License. 17 */ 18 19 import io.netty.channel.ChannelHandlerContext; 20 import io.netty.channel.SimpleChannelInboundHandler; 21 import io.netty.channel.socket.DatagramPacket; 22 import io.netty.util.CharsetUtil; 23 24 public class QuoteOfTheMomentClientHandler extends SimpleChannelInboundHandler<DatagramPacket> { 25 26 @Override 27 public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { 28 String response = msg.content().toString(CharsetUtil.UTF_8); 29 if (response.startsWith("QOTM: ")) { 30 System.out.println("++++Quote of the Moment: " + response.substring(6)); 31 ctx.close(); 32 } 33 } 34 35 @Override 36 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 37 cause.printStackTrace(); 38 ctx.close(); 39 } 40 }
该官方的栗子确实可以很好的实现UDP服务器的功能,甚至你可以写个jedis,与redis链接起来,但是往往项目开发中简单的结合是远远不够的。比如我们要将次UDP服务器与spring框架或者是spring boot框架结合起来,并使用RedisTemplate的操作类访问Redis或者使用JPA链接MySQL的时候,那么该server就要更改了,下一篇文章将会讲解此UDP服务器如何与spring boot框架整合起来,并使用RedisTemplate的操作类访问Redis。
wj:每天努力一点点,你总会成功的。