├── src ├── main │ ├── resources │ │ ├── application-test.properties │ │ ├── application.properties │ │ └── logback.xml │ └── java │ │ └── com │ │ └── example │ │ └── demo │ │ ├── repository │ │ ├── mysql │ │ │ └── UdpRepository.java │ │ └── redis │ │ │ └── RedisRepository.java │ │ ├── LearningUdpApplication.java │ │ ├── mod │ │ └── UdpRecord.java │ │ ├── init │ │ ├── StartupEvent.java │ │ ├── SysConfig.java │ │ └── UdpServer.java │ │ ├── thread │ │ └── TaskExecutePool.java │ │ ├── client │ │ ├── QuoteOfTheMomentClientHandler.java │ │ └── QuoteOfTheMomentClient.java │ │ └── handle │ │ └── UdpServerHandler.java └── test │ └── java │ └── com │ └── example │ └── demo │ └── LearningUdpApplicationTests.java └── pom.xml /src/main/resources/application-test.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wj302763621/learning_udp/HEAD/src/main/resources/application-test.properties -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=test 2 | 3 | spring.messages.encoding=utf-8 4 | 5 | logging.config=classpath:logback.xml -------------------------------------------------------------------------------- /src/main/java/com/example/demo/repository/mysql/UdpRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository.mysql; 2 | 3 | import com.example.demo.mod.UdpRecord; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | /** 7 | * Created by wj on 2017/8/31. 8 | */ 9 | public interface UdpRepository extends JpaRepository { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/com/example/demo/LearningUdpApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class LearningUdpApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/LearningUdpApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableAsync; 6 | import org.springframework.scheduling.annotation.EnableScheduling; 7 | 8 | @SpringBootApplication 9 | @EnableAsync 10 | @EnableScheduling 11 | public class LearningUdpApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(LearningUdpApplication.class, args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/mod/UdpRecord.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.mod; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | import java.sql.Timestamp; 8 | 9 | /** 10 | * Created by wj on 2017/8/31. 11 | * 12 | * 用来记录接收的UDP消息的日志 13 | */ 14 | @Entity 15 | @Table 16 | public class UdpRecord { 17 | 18 | private long id; 19 | private String udpMsg; 20 | private Timestamp time; 21 | 22 | @Id 23 | @GeneratedValue 24 | public long getId() { 25 | return id; 26 | } 27 | 28 | public void setId(long id) { 29 | this.id = id; 30 | } 31 | 32 | public String getUdpMsg() { 33 | return udpMsg; 34 | } 35 | 36 | public void setUdpMsg(String udpMsg) { 37 | this.udpMsg = udpMsg; 38 | } 39 | 40 | public Timestamp getTime() { 41 | return time; 42 | } 43 | 44 | public void setTime(Timestamp time) { 45 | this.time = time; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/repository/redis/RedisRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository.redis; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * 链接redis 11 | * 实现list lpush和rpop 12 | * Created by wj on 2017/8/30. 13 | */ 14 | 15 | 16 | @Service 17 | public class RedisRepository { 18 | private static final Logger log = LoggerFactory.getLogger(RedisRepository.class); 19 | 20 | @Autowired 21 | private RedisTemplate redisTemplate; 22 | 23 | //----------------String----------------------- 24 | public void setKey(String key,String value){ 25 | redisTemplate.opsForValue().set(key, value); 26 | } 27 | 28 | 29 | //----------------list---------------------- 30 | public Long lpush(String key, String val) throws Exception{ 31 | log.info("UDP Msg保存至redis中,key:" + key + ",val:" + val); 32 | return redisTemplate.opsForList().leftPush(key, val); 33 | } 34 | 35 | public String rpop(String key) throws Exception { 36 | return redisTemplate.opsForList().rightPop(key); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/init/StartupEvent.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.init; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.context.event.ContextRefreshedEvent; 8 | 9 | /** 10 | * 11 | * Created by wj on 2017/8/28. 12 | */ 13 | 14 | public class StartupEvent implements ApplicationListener { 15 | private static final Logger log = LoggerFactory.getLogger(StartupEvent.class); 16 | 17 | private static ApplicationContext context; 18 | 19 | @Override 20 | public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { 21 | 22 | try { 23 | 24 | context = contextRefreshedEvent.getApplicationContext(); 25 | 26 | SysConfig sysConfig = (SysConfig) context.getBean(SysConfig.class); 27 | 28 | //接收UDP消息并保存至redis中 29 | UdpServer udpServer = (UdpServer) StartupEvent.getBean(UdpServer.class); 30 | udpServer.run(sysConfig.getUdpReceivePort()); 31 | 32 | 33 | // 这里可以开启多个线程去执行不同的任务 34 | // 此处为工作的内容,不便公开! 35 | 36 | 37 | } catch (Exception e) { 38 | log.error("Exception", e); 39 | } 40 | } 41 | 42 | public static Object getBean(Class beanName) { 43 | return context != null ? context.getBean(beanName) : null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/thread/TaskExecutePool.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.thread; 2 | 3 | import com.example.demo.init.SysConfig; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.scheduling.annotation.EnableAsync; 8 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 9 | 10 | import java.util.concurrent.Executor; 11 | import java.util.concurrent.ThreadPoolExecutor; 12 | 13 | /** 14 | * Created by wangjian on 2017/8/29. 15 | */ 16 | @Configuration 17 | @EnableAsync 18 | public class TaskExecutePool { 19 | 20 | @Autowired 21 | private SysConfig config; 22 | 23 | @Bean 24 | public Executor myTaskAsyncPool() { 25 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 26 | executor.setCorePoolSize(config.getCorePoolSize()); 27 | executor.setMaxPoolSize(config.getMaxPoolSize()); 28 | executor.setQueueCapacity(config.getQueueCapacity()); 29 | executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); 30 | executor.setThreadNamePrefix("MyExecutor-"); 31 | 32 | // rejection-policy:当pool已经达到max size的时候,如何处理新任务 33 | // CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行 34 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 35 | executor.initialize(); 36 | return executor; 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/com/example/demo/init/SysConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.init; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.stereotype.Component; 5 | 6 | /** 7 | * Created by wj on 2017/8/30. 8 | */ 9 | @Component 10 | @ConfigurationProperties(prefix="sysfig") 11 | public class SysConfig { 12 | private int UdpReceivePort;//UDP消息接收端口 13 | 14 | //线程池信息 15 | private int CorePoolSize; 16 | 17 | private int MaxPoolSize; 18 | 19 | private int KeepAliveSeconds; 20 | 21 | private int QueueCapacity; 22 | 23 | public int getCorePoolSize() { 24 | return CorePoolSize; 25 | } 26 | 27 | public void setCorePoolSize(int corePoolSize) { 28 | CorePoolSize = corePoolSize; 29 | } 30 | 31 | public int getMaxPoolSize() { 32 | return MaxPoolSize; 33 | } 34 | 35 | public void setMaxPoolSize(int maxPoolSize) { 36 | MaxPoolSize = maxPoolSize; 37 | } 38 | 39 | public int getKeepAliveSeconds() { 40 | return KeepAliveSeconds; 41 | } 42 | 43 | public void setKeepAliveSeconds(int keepAliveSeconds) { 44 | KeepAliveSeconds = keepAliveSeconds; 45 | } 46 | 47 | public int getQueueCapacity() { 48 | return QueueCapacity; 49 | } 50 | 51 | public void setQueueCapacity(int queueCapacity) { 52 | QueueCapacity = queueCapacity; 53 | } 54 | 55 | public int getUdpReceivePort() { 56 | return UdpReceivePort; 57 | } 58 | 59 | public void setUdpReceivePort(int udpReceivePort) { 60 | UdpReceivePort = udpReceivePort; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/init/UdpServer.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.init; 2 | 3 | import com.example.demo.handle.UdpServerHandler; 4 | import io.netty.bootstrap.Bootstrap; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioDatagramChannel; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.scheduling.annotation.Async; 12 | import org.springframework.stereotype.Component; 13 | 14 | /** 15 | * server服务器 16 | * Created by wj on 2017/8/30. 17 | */ 18 | @Component 19 | public class UdpServer { 20 | 21 | private static final Logger log= LoggerFactory.getLogger(UdpServer.class); 22 | 23 | // private static final int PORT = Integer.parseInt(System.getProperty("port", "7686")); 24 | 25 | @Async("myTaskAsyncPool") 26 | public void run(int udpReceivePort) { 27 | 28 | EventLoopGroup group = new NioEventLoopGroup(); 29 | log.info("Server start! Udp Receive msg Port:" + udpReceivePort ); 30 | 31 | try { 32 | Bootstrap b = new Bootstrap(); 33 | b.group(group) 34 | .channel(NioDatagramChannel.class) 35 | .option(ChannelOption.SO_BROADCAST, true) 36 | .handler(new UdpServerHandler()); 37 | 38 | b.bind(udpReceivePort).sync().channel().closeFuture().await(); 39 | } catch (InterruptedException e) { 40 | e.printStackTrace(); 41 | } finally { 42 | group.shutdownGracefully(); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/client/QuoteOfTheMomentClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.client; 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 { 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 | } 41 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | ${APP_Name} 10 | 11 | 12 | 13 | %d{yyyyMMddHHmmss}|%-5level| %logger{0}.%M | %msg | %thread %n 14 | 15 | 16 | 17 | 18 | 19 | ${catalina.home}/logs/app.%d{yyyyMMdd}.log 20 | 30 21 | 22 | 23 | %d{yyMMddHHmmss.SSS}|%-5level| %msg%n 24 | 25 | 26 | 27 | 28 | 29 | ${catalina.home}/logs/run.%d{yyyyMMdd}.log 30 | 7 31 | 32 | 33 | %d{yyMMddHHmmss.SSS}|%-5level| %msg%n 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/client/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.example.demo.client; 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 | * 此处的UDP发送的客户端是官方公布的客户端 31 | * 在此只是为了测试,不做修改,直接引用 32 | * 33 | * */ 34 | 35 | 36 | /** 37 | * A UDP broadcast client that asks for a quote of the moment (QOTM) to { QuoteOfTheMomentServer}. 38 | * 39 | * Inspired by the official 40 | * Java tutorial. 41 | */ 42 | public final class QuoteOfTheMomentClient { 43 | 44 | static final int PORT = Integer.parseInt(System.getProperty("port", "7686")); 45 | 46 | public static void main(String[] args) throws Exception { 47 | 48 | EventLoopGroup group = new NioEventLoopGroup(); 49 | try { 50 | Bootstrap b = new Bootstrap(); 51 | b.group(group) 52 | .channel(NioDatagramChannel.class) 53 | .option(ChannelOption.SO_BROADCAST, true) 54 | .handler(new QuoteOfTheMomentClientHandler()); 55 | 56 | Channel ch = b.bind(0).sync().channel(); 57 | 58 | String UdpMsg = "Test send udp message to UDPServer!"; 59 | 60 | // Broadcast the QOTM request to port 8080. 61 | ch.writeAndFlush(new DatagramPacket( 62 | Unpooled.copiedBuffer(UdpMsg, CharsetUtil.UTF_8), 63 | SocketUtils.socketAddress("localhost", PORT))).sync(); 64 | 65 | 66 | // QuoteOfTheMomentClientHandler will close the DatagramChannel when a 67 | // response is received. If the channel is not closed within 5 seconds, 68 | // print an error message and quit. 69 | if (!ch.closeFuture().await(5000)) { 70 | System.err.println("QOTM request timed out."); 71 | } 72 | } finally { 73 | group.shutdownGracefully(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/handle/UdpServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.handle; 2 | 3 | import com.example.demo.init.StartupEvent; 4 | import com.example.demo.mod.UdpRecord; 5 | import com.example.demo.repository.mysql.UdpRepository; 6 | import com.example.demo.repository.redis.RedisRepository; 7 | import io.netty.buffer.Unpooled; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import io.netty.channel.SimpleChannelInboundHandler; 10 | import io.netty.channel.socket.DatagramPacket; 11 | import io.netty.util.CharsetUtil; 12 | import org.apache.commons.lang3.StringUtils; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import java.sql.Timestamp; 17 | import java.util.Date; 18 | 19 | /** 20 | * 接受UDP消息,并保存至redis的list链表中 21 | * Created by wj on 2017/8/30. 22 | * 23 | */ 24 | 25 | public class UdpServerHandler extends SimpleChannelInboundHandler { 26 | 27 | private static final Logger log= LoggerFactory.getLogger(UdpServerHandler.class); 28 | 29 | //用来计算server接收到多少UDP消息 30 | private static int count = 0; 31 | 32 | @Override 33 | public void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { 34 | 35 | String receiveMsg = packet.content().toString(CharsetUtil.UTF_8); 36 | 37 | log.info("Received UDP Msg:" + receiveMsg); 38 | 39 | UdpRecord udpRecord = new UdpRecord(); 40 | 41 | //判断接受到的UDP消息是否正确(未实现) 42 | if (StringUtils.isNotEmpty(receiveMsg) ){ 43 | 44 | //计算接收到的UDP消息的数量 45 | count++; 46 | 47 | //获取UdpRepository对象,将接收UDP消息的日志保存至mysql中 48 | udpRecord.setUdpMsg(receiveMsg); 49 | udpRecord.setTime(getTime()); 50 | UdpRepository udpRepository = (UdpRepository) StartupEvent.getBean(UdpRepository.class); 51 | udpRepository.save(udpRecord); 52 | 53 | //获取RedirRepository对象 54 | RedisRepository redisRepository = (RedisRepository) StartupEvent.getBean(RedisRepository.class); 55 | //将获取到的UDP消息保存至redis的list列表中 56 | redisRepository.lpush("udp:msg", receiveMsg); 57 | redisRepository.setKey("UDPMsgNumber", String.valueOf(count)); 58 | 59 | 60 | // 在这里可以返回一个UDP消息给对方,告知已接收到UDP消息,但考虑到这是UDP消息,此处可以注释掉 61 | ctx.write(new DatagramPacket( 62 | Unpooled.copiedBuffer("QOTM: " + "Got UDP Message!" , CharsetUtil.UTF_8), packet.sender())); 63 | 64 | }else{ 65 | log.error("Received Error UDP Messsage:" + receiveMsg); 66 | } 67 | } 68 | 69 | @Override 70 | public void channelReadComplete(ChannelHandlerContext ctx) { 71 | ctx.flush(); 72 | } 73 | 74 | @Override 75 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 76 | cause.printStackTrace(); 77 | // We don't close the channel because we can keep serving requests. 78 | } 79 | 80 | public Timestamp getTime(){ 81 | Date date = new Date(); 82 | Timestamp time = new Timestamp(date.getTime()); 83 | return time; 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | learning_udp 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | learning_udp 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.5.6.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | 30 | 31 | io.netty 32 | netty-all 33 | 4.0.49.Final 34 | 35 | 36 | 37 | org.apache.commons 38 | commons-lang3 39 | 3.4 40 | 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-configuration-processor 46 | true 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-data-jpa 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-jdbc 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-data-redis 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-starter-web 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-starter-web-services 71 | 72 | 73 | 74 | org.springframework.boot 75 | spring-boot-starter-tomcat 76 | provided 77 | 78 | 79 | 80 | org.springframework.boot 81 | spring-boot-starter-test 82 | test 83 | 84 | 85 | 86 | com.h2database 87 | h2 88 | 89 | 90 | 91 | mysql 92 | mysql-connector-java 93 | runtime 94 | 95 | 96 | 97 | joda-time 98 | joda-time 99 | 100 | 101 | 102 | org.apache.httpcomponents 103 | httpclient 104 | 105 | 106 | 107 | 108 | 109 | 110 | org.springframework.boot 111 | spring-boot-maven-plugin 112 | 113 | 114 | 115 | 116 | 117 | 118 | --------------------------------------------------------------------------------