BootNettyChannelInboundHandlerAdapter.java 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package com.lutao.tcp.server.tcptest;
  2. import cn.hutool.core.lang.UUID;
  3. import cn.hutool.http.HttpUtil;
  4. import cn.hutool.json.JSONUtil;
  5. import com.alibaba.fastjson.JSON;
  6. import com.alibaba.fastjson.JSONObject;
  7. import com.lutao.tcp.server.domain.entity.RecSendLog;
  8. import com.lutao.tcp.server.service.RecSendLogService;
  9. import io.netty.channel.ChannelHandlerContext;
  10. import io.netty.channel.ChannelInboundHandlerAdapter;
  11. import lombok.extern.slf4j.Slf4j;
  12. import org.springframework.stereotype.Component;
  13. import javax.annotation.PostConstruct;
  14. import javax.annotation.Resource;
  15. import java.io.IOException;
  16. import java.net.InetSocketAddress;
  17. import java.time.Instant;
  18. import java.time.LocalDateTime;
  19. import java.time.ZoneId;
  20. import java.time.format.DateTimeFormatter;
  21. @Slf4j
  22. @Component
  23. public class BootNettyChannelInboundHandlerAdapter extends ChannelInboundHandlerAdapter {
  24. private static BootNettyChannelInboundHandlerAdapter nettyServerHandler;
  25. @Resource
  26. private RecSendLogService recSendLogService;
  27. @PostConstruct
  28. public void init() {
  29. nettyServerHandler = this;
  30. nettyServerHandler.recSendLogService = this.recSendLogService;
  31. }
  32. /**
  33. * 从客户端收到新的数据时,这个方法会在收到消息时被调用
  34. *
  35. * @param ctx
  36. * @param msg
  37. */
  38. @Override
  39. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception, IOException {
  40. String json = (String) msg;
  41. //log.info(json);
  42. try{
  43. if (msg == null) {
  44. log.error("======加载客户端报文为空======【" + ctx.channel().id() + "】" + " :" + json);
  45. return;
  46. }
  47. if (JSONUtil.isJson(json)){
  48. JSONObject jsonObject = JSON.parseObject(json);
  49. log.info("======加载客户端报文======【" + ctx.channel().id() + "】" + " :" + jsonObject.toJSONString());
  50. RecSendLog recSendLog = new RecSendLog();
  51. String uuid = UUID.randomUUID().toString();
  52. recSendLog.setRec(jsonObject.toJSONString());
  53. recSendLog.setLogType("大范围速报报警");
  54. recSendLog.setCreateTime(LocalDateTime.now());
  55. recSendLog.setUpdateTime(LocalDateTime.now());
  56. recSendLog.setId(uuid);
  57. nettyServerHandler.recSendLogService.save(recSendLog);
  58. //http://115.85.203.230:45002/utility/scopeScan/warnData/submit 转发
  59. String body = HttpUtil.createPost("http://115.85.203.230:45002/utility/scopeScan/warnData/submit")
  60. .body(jsonObject.toJSONString())
  61. .execute().body();
  62. Integer code = JSONUtil.parseObj(body).getInt("code");
  63. log.info("======转发状态码======【" + ctx.channel().id() + "】" + " :" + code);
  64. if (code == 200){
  65. log.info("======转发成功======【" + ctx.channel().id() + "】" + " :" + jsonObject.toJSONString());
  66. recSendLog.setSend(jsonObject.toJSONString());
  67. nettyServerHandler.recSendLogService.updateById(recSendLog);
  68. }else{
  69. log.info("======转发失败======【" + ctx.channel().id() + "】" + " :" + jsonObject.toJSONString());
  70. }
  71. }else{
  72. log.info("======无法转换为json======【" + ctx.channel().id() + "】" + " :" + json);
  73. }
  74. //回应客户端
  75. ctx.write(ctx.channel().id() + "服务端已成功接收数据!");
  76. }catch (Exception e){
  77. e.printStackTrace();
  78. }finally {
  79. }
  80. }
  81. /**
  82. * 从客户端收到新的数据、读取完成时调用
  83. *
  84. * @param ctx
  85. */
  86. @Override
  87. public void channelReadComplete(ChannelHandlerContext ctx) throws IOException {
  88. log.info("channelReadComplete");
  89. ctx.flush();
  90. }
  91. /**
  92. * 当出现 Throwable 对象才会被调用,即当 Netty 由于 IO 错误或者处理器在处理事件时抛出的异常时
  93. *
  94. * @param ctx
  95. * @param cause
  96. */
  97. @Override
  98. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws IOException {
  99. log.info("exceptionCaught");
  100. cause.printStackTrace();
  101. ctx.close();//抛出异常,断开与客户端的连接
  102. }
  103. /**
  104. * 客户端与服务端第一次建立连接时 执行
  105. *
  106. * @param ctx
  107. * @throws Exception
  108. */
  109. @Override
  110. public void channelActive(ChannelHandlerContext ctx) throws Exception, IOException {
  111. super.channelActive(ctx);
  112. ctx.channel().read();
  113. InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
  114. String clientIp = insocket.getAddress().getHostAddress();
  115. //此处不能使用ctx.close(),否则客户端始终无法与服务端建立连接
  116. log.info("channelActive:"+clientIp+ctx.name());
  117. }
  118. /**
  119. * 客户端与服务端 断连时 执行
  120. *
  121. * @param ctx
  122. * @throws Exception
  123. */
  124. @Override
  125. public void channelInactive(ChannelHandlerContext ctx) throws Exception, IOException {
  126. super.channelInactive(ctx);
  127. InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
  128. String clientIp = insocket.getAddress().getHostAddress();
  129. ctx.close(); //断开连接时,必须关闭,否则造成资源浪费,并发量很大情况下可能造成宕机
  130. log.info("channelInactive:"+clientIp);
  131. }
  132. /**
  133. * 服务端当read超时, 会调用这个方法
  134. *
  135. * @param ctx
  136. * @param evt
  137. * @throws Exception
  138. */
  139. @Override
  140. public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception, IOException {
  141. super.userEventTriggered(ctx, evt);
  142. InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
  143. String clientIp = insocket.getAddress().getHostAddress();
  144. ctx.close();//超时时断开连接
  145. log.info("userEventTriggered:"+clientIp);
  146. }
  147. @Override
  148. public void channelRegistered(ChannelHandlerContext ctx) throws Exception{
  149. log.info("channelRegistered");
  150. }
  151. @Override
  152. public void channelUnregistered(ChannelHandlerContext ctx) throws Exception{
  153. //当一个客户端断开连接或一个服务器完成其服务并关闭连接时
  154. log.info("channelUnregistered");
  155. }
  156. /**
  157. * 流量控制是一种拥塞控制机制,
  158. * 用于防止发送方过多地发送数据,从而导致接收方过载。
  159. * 当通道变得不可写时,这可能意味着接收方的缓冲区已满,
  160. * 因此发送方需要停止发送数据,等待通道变得可写时再继续发送
  161. * @throws Exception
  162. */
  163. @Override
  164. public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception{
  165. // 通道变得可写,可以继续发送数据
  166. log.info("Channel is writable, resuming data transmission.");
  167. }
  168. /**
  169. * 广播数据十六进制,每两个字符为一组,
  170. *如:09 57 79 30 30 30 30 30 30 30 30 30 30 30 41 30 30 35 30 30
  171. * 再转为对应ASCII码,即可得到明文的uuid
  172. * @param uuid
  173. */
  174. public String hexToASCII(String uuid) {
  175. StringBuilder sb = new StringBuilder();
  176. for (int i = 0; i < uuid.length(); i += 2) {
  177. String hex = uuid.substring(i, i + 2);
  178. int decimal = Integer.parseInt(hex, 16);
  179. char asciiChar = (char) decimal;
  180. sb.append(asciiChar);
  181. }
  182. String result = sb.toString();
  183. return result;
  184. }
  185. /**
  186. * 将时间戳转换为yyyy-MM-dd HH:mm:ss格式的日期字符串。
  187. * @param timestamp 时间戳(以毫秒为单位)
  188. * @return 格式化后的日期字符串
  189. */
  190. public String timestampToDate(long timestamp) {
  191. Instant instant = Instant.ofEpochSecond(timestamp); // 将时间戳转换为Instant对象
  192. LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); // 将Instant对象转换为本地日期时间对象
  193. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 定义日期格式
  194. // 将日期时间对象格式化为字符串
  195. String time = dateTime.format(formatter);
  196. return time;
  197. }
  198. /**
  199. * 将LocalDateTime转换为yyyy-MM-dd HH:mm:ss格式的日期字符串。
  200. * @return 格式化后的日期字符串
  201. */
  202. public String LocalDateTimeToStr() {
  203. // 获取当前日期时间
  204. LocalDateTime now = LocalDateTime.now();
  205. // 定义日期时间的格式
  206. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  207. // 将LocalDateTime格式化为字符串
  208. String formattedDateTime = now.format(formatter);
  209. return formattedDateTime;
  210. }
  211. }