前言

说实话,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. 【文献阅读】 PVDF &阻尼&有限元建模

    1. 压电Damper原理 Piezoelectric Composite Materials - ScienceDirect 当振动传递到压电材料时,振动能量通过压电效应转化为电能,产生交流电压.所 ...

  2. Selenium IDE工具:火狐浏览器实例讲解IDE命令

    在本文中,通过Firefox浏览器上的示例学习Selenium IDE: 我们将使用的网址是"https://accounts.google.com"作为测试程序,通过本文你会 了 ...

  3. Supervisor-进程守护工具

    前言 Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启.它是通过fork/exec的方式把这些被管理 ...

  4. go sync.map的使用

    前言 数据竞争是并发情况下,存在多线程/协程读写相同数据的情况,必须存在至少一方写.另外,全是读的情况下是不存在数据竞争的. Go语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全 ...

  5. Golang 入门 : 包名与导入路径

    math/rand包有一个Intn函数,可以生成一个随机数,所以我们需要导入math/rand.然后调用rand.Intn生成随机数. 等一下!Intn来自math/rand包,那为什么我们调用包的时 ...

  6. Flask快速入门1

    因为新换了一个工作,项目使用了Flask框架技术,需要快速学习下,学过Django这个重量级的框架基础后,再去学习Flask框架相对还是容易的. 当然入门基础容易,要深入理解还是要慢慢花时间深耕练习使 ...

  7. MOS管的引脚,G、S、D分别代表什么?

    引脚解析: G:gate 栅极,N沟道的电源一般接在D. S:source 源极,输出S,P沟道的电源一般接在S. D:drain 漏极,输出D.增强耗尽接法基本一样. mos管是金属(metal)- ...

  8. 算法图解,关于数组,链表,以及大O表示法

    有关数组.链表以及大O表示法 关于数组 [1] 连续性:数组在内存中连续储存,就像是看电影的一群人排排坐. [2] 易读性:数组中的元素可以随意读取. [3] 难改性:由于连续的特性,增减元素都会导致 ...

  9. 可视化|数据可视化文档之 echarts 项目初始化

    数据可视化文档之 echarts 项目初始化 环境搭建 # node 环境 nvm install v11.15.0 # or nvm use 11.15.0 # 查看 node 版本 node -V ...

  10. Delphi 检测鼠标键盘多久没有活动

    function GetInputAwayTime():DWORD; var lpi:TLastInputInfo; begin lpi.cbSize := sizeof(lpi); GetLastI ...