前言

说实话,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的更多相关文章

  1. java tcp socket实例

    java tcp socket实例 2011-04-20 13:58 2364人阅读 评论(1) 收藏 举报 socketjavatcpthreadserverclass package com.ne ...

  2. java netty socket库和自定义C#socket库利用protobuf进行通信完整实例

    之前的文章讲述了socket通信的一些基本知识,已经本人自定义的C#版本的socket.和java netty 库的二次封装,但是没有真正的发表测试用例. 本文只是为了讲解利用protobuf 进行C ...

  3. java nio socket实例

    Server端代码: public class NioServer { //通道管理器 private Selector selector; //获取一个ServerSocket通道,并初始化通道 p ...

  4. java 文本读取 写入指定长度的内容

  5. SuperSocket 1.6 创建一个简易的报文长度在头部的Socket服务器

    我们来做一个头为6位报文总长度,并且长度不包含长度域自身的例子.比如这样的Socket报文000006123456. 添加SuperSocket.Engine,直接使用Nuget搜索SuperSock ...

  6. Java nio socket与as3 socket(粘包解码)连接的应用实例

    对Java nio socket与as3 socket连接的简单应用 <ignore_js_op>Java nio socket与as3 socket连接的应用实例.rar (9.61 K ...

  7. Flex通信-与Java实现Socket通信实例

    Flex通信-与Java实现Socket通信实例  转自:http://blessht.iteye.com/blog/1136888 博客分类: Flex 环境准备 [服务器端] JDK1.6,“ja ...

  8. Java的Socket通信简单实例

    服务端 package testlxd; import java.io.BufferedReader; import java.io.IOException; import java.io.Input ...

  9. 2011 wireshark 实用过滤表达式(针对ip、协议、端口、长度和内容) 实例介绍

    首先说几个最常用的关键字,“eq” 和 “==”等同,可以使用 “and” 表示并且,“or”表示或者.“!" 和 "not” 都表示取反. 一.针对wireshark最常用的自然 ...

  10. tcpdump wireshark 实用过滤表达式(针对ip、协议、端口、长度和内容) 实例介绍

    tcpdump wireshark 实用过滤表达式(针对ip.协议.端口.长度和内容) 实例介绍 标签: 网络tcpdst工具windowslinux 2012-05-15 18:12 3777人阅读 ...

随机推荐

  1. 【Python】基础操作

    指定解释器的运行环境 有时候我们会遇见报错 SyntaxError: Non-ASCII character '\xe4' in file E:/PycharmProjects/LEDdisplay2 ...

  2. 记载火狐浏览器下的一次新手级的js解密工作

    警告:该随笔内容仅用于合法范围下的学习,不得用于任何商业和非法用途,不得未经授权转载,否则后果自负. 首先是需要解密的网站:https://www.aqistudy.cn/historydata/mo ...

  3. Semaphore.release()方法的底层原理

    一.release() 方法代码解析 当调用 release() 方法时,实际调用的是 AQS 的 releaseShared(1) 方法.以下是其详细工作流程: public final boole ...

  4. SynchronousQueue的put方法底层源码

    一.SynchronousQueue的put方法底层源码 SynchronousQueue 的 put 方法用于将元素插入队列.由于 SynchronousQueue 没有实际的存储空间,put 方法 ...

  5. 多模态自动驾驶混合渲染HRMAD:将NeRF和3DGS进行感知验证和端到端AD测试

    基于3DGS和NeRF的三维重建技术在过去的一年中取得了快速的进步,动态模型也变得越来越普遍,然而这些模型仅限于处理原始轨迹域内的对象. HRMAD作为一种混合方案,将传统的基于网格的动态三维神经重建 ...

  6. DPDI(Dispatch PDI)kettle调度管理平台环境部署升级

    1.DPDI演示环境 DPDI online登录域名:http://dpdi.pizzalord.site 用户名:dpdi 密 码:dpdi 2.DPDI下载 DPDI online部署包下载地址: ...

  7. AutoFac(三)——装配扫描(批量注册之扫描模块)

    RegisterAssemblyModules() 模块扫描使用RegisterAssemblyModules()注册方法执行,该方法完全按照其名称执行.它扫描提供的Autofac模块的程序集,创建模 ...

  8. Python3 GUI界面

    一.python gui(图形化)模块介绍: Tkinter :是python最简单的图形化模块,总共只有14种组建 Pyqt :是python最复杂也是使用最广泛的图形化 Wx :是python当中 ...

  9. UnicodeDecodeError: ‘ascii‘ codec can‘t decode byte 0xe8 in position...解决方法

    运行python程序,出现了以下错误: File "C:/��͸/python ѧϰ/god_mellonѧϰpython/untitled2/fofa_py2.py", line ...

  10. windows 隐藏桌面了解此图片

    1. 桌面上有了解此图片图标无法删除 这是因为在windows背景设置中选择了Window聚焦. 如果想关闭可以选择其他选项.如果不想关闭Window聚焦还想隐藏桌面了解此图片图标,可以参考下面设置. ...