java netty socket实例:报文长度+报文内容,springboot
前言
说实话,java netty方面的资料不算多,尤其是自定义报文格式的,少之又少
自己写了个简单的收发:报文长度+报文内容
发送的话,没有写自动组装格式,自己看需求吧,需要的话,自己完善
服务端启动
可以直接用类文件启动,也可以通过springboot。我这里写的是用springboot启动的,可以自己按照需求自己修改
代码
入口
package cn.daenx.demo.example.socket;
import cn.daenx.demo.example.service.BankServerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* 入口
*
* @author DaenMax
*/
@Slf4j
@Component
public class SocketServer {
/**
* 这里仅仅是为了注入一个处理消息的service接口
*/
@Resource
private BankServerService bankServerService;
@PostConstruct
public void start() {
SocketServerThread socketServerThread = new SocketServerThread(bankServerService);
socketServerThread.start();
}
}
服务端
package cn.daenx.demo.example.socket;
import cn.daenx.demo.example.service.BankServerService;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
/**
* 服务端
*
* @author DaenMax
*/
@Slf4j
@Component
public class SocketServerThread extends Thread {
private static BankServerService bankServerService;
public SocketServerThread(BankServerService bankServerService) {
this.bankServerService = bankServerService;
}
//监听IP
private static final String ip = "127.0.0.1";
//监听端口
private static final int port = 6666;
//发送的数据帧最大长度
private static final int maxFrameLength = Integer.MAX_VALUE;
//定义长度域位于发送的字节数组中的下标
private static final int lengthFieldOffset = 0;
//用于描述定义的长度域的长度默认只支持 1, 2, 3, 4, or 8(原版)
//我这里重写了解码器,所以支持传入任意长度
private static final int lengthFieldLength = 6;
//偏移位,即:长度字节和内容中间隔了几个字节
private static final int lengthAdjustment = 0;
//表示获取完一个完整的数据包之后,忽略前面的几个字节
private static final int initialBytesToStrip = 6;
private static final EventLoopGroup bossGroup = new NioEventLoopGroup();
private static final EventLoopGroup workerGroup = new NioEventLoopGroup();
@Override
public void run() {
log.info("SocketServer启动中...");
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<Channel>() {
protected void initChannel(Channel ch) {
ChannelPipeline pipeline = ch.pipeline();
ch.pipeline().addLast(new CustomLengthFieldDecoder(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip));
pipeline.addLast(new SocketHandler(bankServerService));
}
});
ChannelFuture channelFuture = serverBootstrap.bind(ip, port).sync();
log.info("SocketServer启动完成,端口:" + port);
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}
}
@PreDestroy
public void preDestroy() {
log.info("springboot项目即将停止运行");
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
log.info("SocketServer已停止,端口:" + port);
}
}
事件处理器
package cn.daenx.demo.example.socket;
import cn.daenx.demo.example.service.BankServerService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
/**
* 事件处理器
*
* @author DaenMax
*/
@Slf4j
public class SocketHandler extends ChannelInboundHandlerAdapter {
private final BankServerService bankServerService;
public SocketHandler(BankServerService bankServerService) {
this.bankServerService = bankServerService;
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
}
/**
* 接收到的报文
* 注意,因为用了LengthFieldBasedFrameDecoder,所以这里不会分包,而是会一次性接收完成后才会调用此方法
*
* @param ctx
* @param msg
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf message = (ByteBuf) msg;
byte[] response = new byte[message.readableBytes()];
message.readBytes(response);
String reqStr = new String(response);
log.info("接收socket->>>" + reqStr);
String resStr = bankServerService.handleReqXml(reqStr);
ByteBuf sendMsg = Unpooled.buffer(resStr.length());
sendMsg.writeBytes(resStr.getBytes());
ctx.writeAndFlush(sendMsg);
log.info("响应socket->>>" + resStr);
}
/**
* 发生异常时
*
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
String resStr = "出现错误,请联系运维人员";
ByteBuf sendMsg = Unpooled.buffer(resStr.length());
sendMsg.writeBytes(resStr.getBytes());
ctx.writeAndFlush(sendMsg);
log.info("响应socket->>>" + resStr);
ctx.close();
}
/**
* 获取IP地址
*/
private String getIP(ChannelHandlerContext ctx) {
String socketString = ctx.channel().remoteAddress().toString();
int index = socketString.indexOf(":");
String ip = socketString.substring(1, index);
return ip;
}
}
自定义定长解码器
package cn.daenx.demo.example.socket;
import cn.hutool.core.util.CharsetUtil;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.TooLongFrameException;
import java.nio.ByteOrder;
/**
* LengthFieldBasedFrameDecoder长度域的长度默认只支持 1, 2, 3, 4, or 8
* 但是我的需求是6位长度域,所以继承重写getUnadjustedFrameLength方法
*
* @author DaenMax
*/
public class CustomLengthFieldDecoder extends LengthFieldBasedFrameDecoder {
/**
* Creates a new instance.
*
* @param maxFrameLength the maximum length of the frame. If the length of the frame is
* greater than this value, {@link TooLongFrameException} will be
* thrown.
* @param lengthFieldOffset the offset of the length field
* @param lengthFieldLength the length of the length field
* @param lengthAdjustment the compensation value to add to the value of the length field
* @param initialBytesToStrip
*/
public CustomLengthFieldDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
}
/**
* 重写getUnadjustedFrameLength方法,可以自定义长度区域字节数
*
* @param buf
* @param offset
* @param length
* @param order
* @return
*/
@Override
protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
buf = buf.order(order);
CharSequence frameLength = buf.getCharSequence(0, length, CharsetUtil.CHARSET_UTF_8);
Long lengthLength = Long.valueOf((String) frameLength);
return lengthLength.longValue();
}
}
service接口
package cn.daenx.demo.example.service.impl;
import cn.daenx.demo.example.service.BankServerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 处理Socket请求
*
* @author DaenMax
*/
@Slf4j
@Service
public class BankServerServiceImpl implements BankServerService {
/**
* 处理Socket请求
*
* @param str
* @return
*/
@Override
public String handleReqXml(String str) {
return "我已成功收到你的请求";
}
}
发送接收方法testSocketSend
package cn.daenx.demo.example.socket;
import java.io.*;
import java.net.Socket;
/**
* 测试发送和接收
*
* @author DaenMax
*/
public class testSocketSend {
//测试发送和接收
public static void main(String[] args) throws Exception {
System.out.println(send("127.0.0.1", "6666", "0051203f478ff4846dbdc1cbd32b44cee63658c9fc7535104bac402b8b3b997def5a24ab21e99ce1852de2a6d3877bc83c13076350433509d8b7d2b4447af019a415e81ff82b94d97f54a1b3b0698569cde81faa0ca5845aef1df3433637d6d4f374faac1953a1bc9ee147d1ac2e72e8b03758a76deea7464360e906924c28cbed37a6c41bc3c641c29542f5cc99846bc34963e51011b3c76b49d5e5a3b714215f55cc9bfbb6e0cf080a5cca57931a5d211b5723e99e0c74be56de2b5950d2a90909f1346f90281088df55d025cf5f3ec8280c7fc4feb36eef29029627d2a2bfa7cdb80ce85e34281629204a69876c43de88cd05baba70bc7ba50e9fa89838ca30855d87647847f203aa0daec68b7b434ffe4d8275355b535205424fde56bf185d6acae2e140fbc00ec5b26084a8b2d9def1459416170143a7a597466fdd92c8ee735c5d1db837b5ed96b462130de4cea2d9e95c84171acaedaef1aa2d25ce7f4078d80b115e9b0cb026672b751e3843b7f5fba23d60ee1d576f2354468655bbe1c4eb787b0aaf754a16dfbc6763ea1625b07e2b9c7a26a379857936db479494de17e063a2378ca1d4ae1dba1779cc792adb423068a0df1e7eb522186f17ae489860aeb6ec569d73c9303c7a5e2f8716a32140ccea074999c43e86eef31dd9754142dfa03bb3b7c2381fa229f8034f3ea542b321a502b340df33fd4af7ac7c81eba1173f478ff4846dbdc1cbd32b44cee63658c9fc7535104bac402b8b3b997def5a24ab21e99ce1852de2a6d3877bc83c13076350433509d8b7d2b4447af019a415e81ff82b94d97f54a1b3b0698569cde81faa0ca5845aef1df3433637d6d4f374faac1953a1bc9ee147d1ac2e72e8b03758a76deea7464360e906924c28cbed37a6c41bc3c641c29542f5cc99846bc34963e51011b3c76b49d5e5a3b714215f55cc9bfbb6e0cf080a5cca57931a5d211b5723e99e0c74be56de2b5950d2a90909f1346f90281088df55d025cf5f3ec8280c7fc4feb36eef29029627d2a2bfa7cdb80ce85e34281629204a69876c43de88cd05baba70bc7ba50e9fa89838ca30855d87647847f203aa0daec68b7b434ffe4d8275355b535205424fde56bf185d6acae2e140fbc00ec5b26084a8b2d9def1459416170143a7a597466fdd92c8ee735c5d1db837b5ed96b462130de4cea2d9e95c84171acaedaef1aa2d25ce7f4078d80b115e9b0cb026672b751e3843b7f5fba23d60ee1d576f2354468655bbe1c4eb787b0aaf754a16dfbc6763ea1625b07e2b9c7a26a379857936db479494de17e063a2378ca1d4ae1dba1779cc792adb423068a0df1e7eb522186f17ae489860aeb6ec569d73c9303c7a5e2f8716a32140ccea074999c43e86eef31dd9754142dfa03bb3b7c2381fa229f8034f3ea542b321a502b340df33fd4af7ac7c81eba1173f478ff4846dbdc1cbd32b44cee63658c9fc7535104bac402b8b3b997def5a24ab21e99ce1852de2a6d3877bc83c13076350433509d8b7d2b4447af019a415e81ff82b94d97f54a1b3b0698569cde81faa0ca5845aef1df3433637d6d4f374faac1953a1bc9ee147d1ac2e72e8b03758a76deea7464360e906924c28cbed37a6c41bc3c641c29542f5cc99846bc34963e51011b3c76b49d5e5a3b714215f55cc9bfbb6e0cf080a5cca57931a5d211b5723e99e0c74be56de2b5950d2a90909f1346f90281088df55d025cf5f3ec8280c7fc4feb36eef29029627d2a2bfa7cdb80ce85e34281629204a69876c43de88cd05baba70bc7ba50e9fa89838ca30855d87647847f203aa0daec68b7b434ffe4d8275355b535205424fde56bf185d6acae2e140fbc00ec5b26084a8b2d9def1459416170143a7a597466fdd92c8ee735c5d1db837b5ed96b462130de4cea2d9e95c84171acaedaef1aa2d25ce7f4078d80b115e9b0cb026672b751e3843b7f5fba23d60ee1d576f2354468655bbe1c4eb787b0aaf754a16dfbc6763ea1625b07e2b9c7a26a379857936db479494de17e063a2378ca1d4ae1dba1779cc792adb423068a0df1e7eb522186f17ae489860aeb6ec569d73c9303c7a5e2f8716a32140ccea074999c43e86eef31dd9754142dfa03bb3b7c2381fa229f8034f3ea542b321a502b340df33fd4af7ac7c81eba1173f478ff4846dbdc1cbd32b44cee63658c9fc7535104bac402b8b3b997def5a24ab21e99ce1852de2a6d3877bc83c13076350433509d8b7d2b4447af019a415e81ff82b94d97f54a1b3b0698569cde81faa0ca5845aef1df3433637d6d4f374faac1953a1bc9ee147d1ac2e72e8b03758a76deea7464360e906924c28cbed37a6c41bc3c641c29542f5cc99846bc34963e51011b3c76b49d5e5a3b714215f55cc9bfbb6e0cf080a5cca57931a5d211b5723e99e0c74be56de2b5950d2a90909f1346f90281088df55d025cf5f3ec8280c7fc4feb36eef29029627d2a2bfa7cdb80ce85e34281629204a69876c43de88cd05baba70bc7ba50e9fa89838ca30855d87647847f203aa0daec68b7b434ffe4d8275355b535205424fde56bf185d6acae2e140fbc00ec5b26084a8b2d9def1459416170143a7a597466fdd92c8ee735c5d1db837b5ed96b462130de4cea2d9e95c84171acaedaef1aa2d25ce7f4078d80b115e9b0cb026672b751e3843b7f5fba23d60ee1d576f2354468655bbe1c4eb787b0aaf754a16dfbc6763ea1625b07e2b9c7a26a379857936db479494de17e063a2378ca1d4ae1dba1779cc792adb423068a0df1e7eb522186f17ae489860aeb6ec569d73c9303c7a5e2f8716a32140ccea074999c43e86eef31dd9754142dfa03bb3b7c2381fa229f8034f3ea542b321a502b340df33fd4af7ac7c81eba1173f478ff4846dbdc1cbd32b44cee63658c9fc7535104bac402b8b3b997def5a24ab21e99ce1852de2a6d3877bc83c13076350433509d8b7d2b4447af019a415e81ff82b94d97f54a1b3b0698569cde81faa0ca5845aef1df3433637d6d4f374faac1953a1bc9ee147d1ac2e72e8b03758a76deea7464360e906924c28cbed37a6c41bc3c641c29542f5cc99846bc34963e51011b3c76b49d5e5a3b714215f55cc9bfbb6e0cf080a5cca57931a5d211b5723e99e0c74be56de2b5950d2a90909f1346f90281088df55d025cf5f3ec8280c7fc4feb36eef29029627d2a2bfa7cdb80ce85e34281629204a69876c43de88cd05baba70bc7ba50e9fa89838ca30855d87647847f203aa0daec68b7b434ffe4d8275355b535205424fde56bf185d6acae2e140fbc00ec5b26084a8b2d9def1459416170143a7a597466fdd92c8ee735c5d1db837b5ed96b462130de4cea2d9e95c84171acaedaef1aa2d25ce7f4078d80b115e9b0cb026672b751e3843b7f5fba23d60ee1d576f2354468655bbe1c4eb787b0aaf754a16dfbc6763ea1625b07e2b9c7a26a379857936db479494de17e063a2378ca1d4ae1dba1779cc792adb423068a0df1e7eb522186f17ae489860aeb6ec569d73c9303c7a5e2f8716a32140ccea074999c43e86eef31dd9754142dfa03bb3b7c2381fa229f8034f3ea542b321a502b340df33fd4af7ac7c81eba666"));
}
/**
* 发送消息到指定服务上
*
* @param host
* @param port
* @param msg
* @return
*/
public static String send(String host, String port, String msg) throws Exception {
try (Socket socket = new Socket(host, Integer.parseInt(port));) {
OutputStream outputStream = socket.getOutputStream();
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.print(msg);
printWriter.flush();
socket.shutdownOutput();
System.out.println("socket发送,host=" + host + ",port=" + port + ",msg=" + msg);
//获取一个输入流,接收服务端的信息
InputStream inputStream = socket.getInputStream();
//包装成字符流,提高效率
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
//缓冲区
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuffer sb = new StringBuffer();
//临时变量
String temp = null;
while ((temp = bufferedReader.readLine()) != null) {
sb.append(temp).append("\n");
}
System.out.println("socket接收,host=" + host + ",port=" + port + ",msg=" + sb.toString());
//关闭相对应的资源
bufferedReader.close();
inputStream.close();
printWriter.close();
outputStream.close();
socket.close();
String ret = sb.toString();
return ret;
} catch (IOException e) {
throw new Exception("连接服务失败");
}
}
}
测试
先启动springboot
然后直接运行testSocketSend即可看到效果
java netty socket实例:报文长度+报文内容,springboot的更多相关文章
- java tcp socket实例
java tcp socket实例 2011-04-20 13:58 2364人阅读 评论(1) 收藏 举报 socketjavatcpthreadserverclass package com.ne ...
- java netty socket库和自定义C#socket库利用protobuf进行通信完整实例
之前的文章讲述了socket通信的一些基本知识,已经本人自定义的C#版本的socket.和java netty 库的二次封装,但是没有真正的发表测试用例. 本文只是为了讲解利用protobuf 进行C ...
- java nio socket实例
Server端代码: public class NioServer { //通道管理器 private Selector selector; //获取一个ServerSocket通道,并初始化通道 p ...
- java 文本读取 写入指定长度的内容
- SuperSocket 1.6 创建一个简易的报文长度在头部的Socket服务器
我们来做一个头为6位报文总长度,并且长度不包含长度域自身的例子.比如这样的Socket报文000006123456. 添加SuperSocket.Engine,直接使用Nuget搜索SuperSock ...
- Java nio socket与as3 socket(粘包解码)连接的应用实例
对Java nio socket与as3 socket连接的简单应用 <ignore_js_op>Java nio socket与as3 socket连接的应用实例.rar (9.61 K ...
- Flex通信-与Java实现Socket通信实例
Flex通信-与Java实现Socket通信实例 转自:http://blessht.iteye.com/blog/1136888 博客分类: Flex 环境准备 [服务器端] JDK1.6,“ja ...
- Java的Socket通信简单实例
服务端 package testlxd; import java.io.BufferedReader; import java.io.IOException; import java.io.Input ...
- 2011 wireshark 实用过滤表达式(针对ip、协议、端口、长度和内容) 实例介绍
首先说几个最常用的关键字,“eq” 和 “==”等同,可以使用 “and” 表示并且,“or”表示或者.“!" 和 "not” 都表示取反. 一.针对wireshark最常用的自然 ...
- tcpdump wireshark 实用过滤表达式(针对ip、协议、端口、长度和内容) 实例介绍
tcpdump wireshark 实用过滤表达式(针对ip.协议.端口.长度和内容) 实例介绍 标签: 网络tcpdst工具windowslinux 2012-05-15 18:12 3777人阅读 ...
随机推荐
- Avalanche公链深度解析:创新共识、亚秒级最终性与生态竞争力
摘要:Avalanche定位为一个高性能.可扩展的Layer 1区块链平台,但它并不是一个新公链,其主网于2020年9月21日正式上线,有Ava Labs开发.Ava Labs成立于2018年,总部位 ...
- WSL2 - Ubuntu 22.04使用记录
1 安装 搭配Windows Terminal使用为佳,在微软商店可下载: 然后依照官网描述即可. 命令行中运行wsl --install即可.不过由于想自行指定发行版,于是: wsl --list ...
- 使用react-native-drawer,跟着官网配置仍报错,Error: [Reanimated] `valueUnpacker` is not a worklet, js engine: hermes
在使用react-native-drawer组件时,编译项目报错 试了许多的方法,最后通过在一篇博客中找到解决方法https://blog.csdn.net/lxyoucan/article/deta ...
- Ansible运行临时命令
一.基本语法格式: 格式:ansible 受控主机IP/主机组 [选项] 参数 选项 -k 手动输入SSH协议的代码 -l 指定主机清单文件 -m 指定要使用的模块名 -a 设置传递给模块的参数 -M ...
- oracle 数据库服务名怎么查
WINDOWS上,直接看 服务里的 服务名就好:Oracle SID Service ,中间的SID就是数据库服务的名称.LINUX系统下,输入env |grep SID 可以查看到,一般没换都是这个 ...
- 【长知识】BIOS
设置最新UEFI BIOS 本章导读 BIOS是电脑启动和操作的基础,若电脑系统中没有BIOS,则所有硬件设备都不能正常使用.UEFI是目前最新的BIOS类型,以后会逐渐取代传统的BIOS.本章将认识 ...
- 请运行命令来卸载Oracle主目录
卸载Oracle数据库碰见的一个不一样的操作,留爪. 正常点的软件卸载直接点卸载即可, Oracle 卸载非要来点不一样警告, 如图: 注意:不要被图里的斜杠符号忽略了,准确的应该是: # 注意斜杠 ...
- 武汉工程大学2020GPLT选拔赛(重现赛)
L2-4 缘之空 1.使用倍增法求最近公共祖先,然后利用公共祖先计算两点的树上距离 2.但是此题并没有提供根节点,所以要先找到根节点以后才可以进行倍增法求lca /** - swj - * /> ...
- springboot和jdk的版本对应关系
spring-boot和jdk的版本对应关系 SpringBoot Versions JDK Versions 0.0 -1.1 6+(6 or higher) 1.2 - 1.5 6 - 7 2.0 ...
- vue 前端选择弹窗取值完整实例[经典]
<!-- 班次信息 --> <el-row> <el-col :span="24"> <el-form-item label=" ...