高性能TcpServer(Java) - Netty
Netty 是一个高性能、异步事件驱动的 NIO 框架,它提供了对 TCP、UDP 和文件传输的支持,作为一个异步 NIO 框架,Netty 的所有 IO 操作都是异步非阻塞的,通过 Future-Listener 机制,用户可以方便的主动获取或者通过通知机制获得 IO 操作结果。
作为当前最流行的 NIO 框架,Netty 在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,一些业界著名的开源组件也基于 Netty 的 NIO 框架构建。
协议解析代码:
package nettyserver;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import java.util.HashMap;
import java.util.Map;
class MyInHandler extends ChannelInboundHandlerAdapter {
final byte HEAD1 = 0x48;// H
final byte HEAD2 = 0x54;// T
final byte HEAD3 = 0x45;// E
final byte HEAD4 = 0x4D;// M
final byte HEAD5 = 0x50;// P
final byte HEAD6 = 0x3D;// =
public static final String SPLIT1 = "#";
public static Map<String, io.netty.buffer.ByteBuf> dicSn2Buffer = new HashMap<>();
// HTEMP=0026#1533022506#Meter-001#01##
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
{
// 当出现异常就关闭连接
//cause.printStackTrace();
RemoveClient(ctx, "exceptionCaught");
}
@Override
public void channelActive(io.netty.channel.ChannelHandlerContext ctx) throws Exception
{
CTxtHelp.AppendLog("客户端已经连接,sn:" + GetSN(ctx));
}
@Override
public void channelInactive(io.netty.channel.ChannelHandlerContext ctx) throws Exception
{
RemoveClient(ctx, "channelInactive");
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception
{
if (evt instanceof IdleStateEvent)
{
String type = "未知";
IdleStateEvent event = (IdleStateEvent) evt;
if (null != event.state())
{
switch (event.state())
{
case READER_IDLE: type = "read idle"; break;
case WRITER_IDLE: type = "write idle"; break;
case ALL_IDLE: type = "all idle"; break;
default: break;
}
}
RemoveClient(ctx, "超时退出(" + type + ")");
}
else
{
super.userEventTriggered(ctx, evt);
}
}
@Override
public void channelRead(io.netty.channel.ChannelHandlerContext ctx, Object msg)
{
if (!ctx.channel().isActive()) return;
String sn = GetSN(ctx);
if(!dicSn2Buffer.containsKey(sn)) dicSn2Buffer.put(sn, Unpooled.buffer(1024));
io.netty.buffer.ByteBuf oldBuffer = dicSn2Buffer.get(sn);
if (null != msg)
{
io.netty.buffer.ByteBuf recvBuffer = (ByteBuf) msg;
int size = recvBuffer.readableBytes();
if (size > 0)
{
//recvBuffer.markReaderIndex();
oldBuffer.writeBytes(recvBuffer);
ReferenceCountUtil.release(recvBuffer);
//recvBuffer.resetReaderIndex();
//byte[] recv = new byte[size];
//recvBuffer.readBytes(recv);
//CTxtHelp.AppendLog("接收数据:" + CDataHelper.ArrayByteToString(recv));
}
}
byte head1 = 0; byte head2 = 0; byte head3 = 0; byte head4 = 0; byte head5 = 0; byte head6 = 0;
while (oldBuffer.isReadable())
{
oldBuffer.markReaderIndex();
head1 = oldBuffer.readByte(); if (!oldBuffer.isReadable()) { oldBuffer.resetReaderIndex(); return ; } // 掉包处理
if (HEAD1 == head1)// 垃圾包处理
{
head2 = oldBuffer.readByte(); if (!oldBuffer.isReadable()) { oldBuffer.resetReaderIndex(); return ; }
head3 = oldBuffer.readByte(); if (!oldBuffer.isReadable()) { oldBuffer.resetReaderIndex(); return ; }
head4 = oldBuffer.readByte(); if (!oldBuffer.isReadable()) { oldBuffer.resetReaderIndex(); return ; }
head5 = oldBuffer.readByte(); if (!oldBuffer.isReadable()) { oldBuffer.resetReaderIndex(); return ; }
head6 = oldBuffer.readByte(); if (!oldBuffer.isReadable()) { oldBuffer.resetReaderIndex(); return ; }
if (HEAD2 == head2 && HEAD3 == head3 && HEAD4 == head4 && HEAD5 == head5 && HEAD6 == head6)
{
break;
}
else
{
CTxtHelp.AppendLog("Error,Unable to parse the data2");
}
}
else
{
CTxtHelp.AppendLog("Error,Unable to parse the data1");
}
}
int lengthsize = 4;
if (GetWaitRecvRemain(oldBuffer, lengthsize)) { oldBuffer.resetReaderIndex(); return ; }
byte[] arrlen = new byte[lengthsize]; oldBuffer.readBytes(arrlen);
int lengthdata = CDataHelper.String2Int(CDataHelper.ArrayByteToString(arrlen));// if (-1 == len) return;
if (GetWaitRecvRemain(oldBuffer, lengthdata)) { oldBuffer.resetReaderIndex(); return ; }
byte[] source = new byte[lengthdata]; oldBuffer.readBytes(source);
String data = CDataHelper.ArrayByteToString(source);
CTxtHelp.AppendLog("解析后:" + data);
if (null == data || 0 == data.length() || data.length() - 1 != data.lastIndexOf(SPLIT1)) return;
data = data.substring(1, data.length() - 1);
String[] items = data.split(SPLIT1, -1);
if (null == items || 4 != items.length) return;
String uid = items[0];
String taskid = items[1];
int cmd = CDataHelper.String2Int(items[2]);
String content = items[3];
String back = "";
try
{
switch (cmd)
{
case 1: back = "ok"; break;
case 2: break;
case 3: break;
}
}
catch (Exception ex)
{
CTxtHelp.AppendLog("error@" + ex.getMessage());
}
if (!"".equals(back))
{
byte[] sendBuff = GetProtocol(uid, cmd, back);
ByteBuf out = ctx.alloc().directBuffer(sendBuff.length);
out.writeBytes(sendBuff);
ctx.channel().writeAndFlush(out);
}
if (!oldBuffer.isReadable())
{
oldBuffer.clear();
}
else
{
channelRead(ctx, null);
}
}
boolean GetWaitRecvRemain( io.netty.buffer.ByteBuf buf, int len) {
return buf.readerIndex() + len > buf.writerIndex();
}
String GetSN(io.netty.channel.ChannelHandlerContext ctx)
{
return ctx.channel().remoteAddress().toString().replace("/", "");
}
void RemoveClient(io.netty.channel.ChannelHandlerContext ctx, String errmsg)
{
String sn = GetSN(ctx);
CTxtHelp.AppendLog("客户端退出,errmsg:" + errmsg);
if(dicSn2Buffer.containsKey(sn)) {
io.netty.buffer.ByteBuf byteBuf = dicSn2Buffer.get(sn);
ReferenceCountUtil.release(byteBuf);
dicSn2Buffer.remove(sn);
}
ctx.close();
}
byte[] GetProtocol(String uid, int cmd, String msg)
{
String content = SPLIT1 + uid + SPLIT1 +
System.currentTimeMillis() + SPLIT1 +
CDataHelper.lpad(cmd, 2) + SPLIT1 +
msg + SPLIT1;
StringBuilder data = new StringBuilder();
data.append("HTEMP=");
data.append(CDataHelper.lpad(CDataHelper.GetStringLength(content), 4));
data.append(content);
return CDataHelper.StringToByte(data.toString());
}
String lpad(int number, int length) {
String f = "%0" + length + "d";
return String.format(f, number);
}
}
程序结构:

运行结果:
1. 包解析(正常包+掉包+粘包+垃圾包)

2. 超时清理链路

3. 并发测试

高性能TcpServer(Java) - Netty的更多相关文章
- Java Netty简介
Netty和Mina是Java世界非常知名的通讯框架.它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户netty.io(http:// ...
- [转帖]Java Netty简介
Java Netty简介 https://www.cnblogs.com/ghj1976/p/3779820.html Posted on 2014-06-10 13:41 蝈蝈俊 阅读(2992) ...
- java netty socket库和自定义C#socket库利用protobuf进行通信完整实例
之前的文章讲述了socket通信的一些基本知识,已经本人自定义的C#版本的socket.和java netty 库的二次封装,但是没有真正的发表测试用例. 本文只是为了讲解利用protobuf 进行C ...
- 【Jetlang】一个高性能的Java线程库
actor Jetlang 提供了一个高性能的Java线程库,该库是 JDK 1.5 中的 java.util.concurrent 包的补充,可用于基于并发消息机制的应用. .net的MS CCR ...
- JAVA语言之怎样写出高性能的Java代码?
本文主要向大家介绍了JAVA语言之怎样写出高性能的 Java 代码?通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 在这篇文章中,我们将讨论几个有助于提升Java应用程序性能的方法.我 ...
- 项目-高性能TcpServer - 目录
1.项目-高性能TcpServer - 1.网络通信协议 https://blog.csdn.net/arno1988/article/details/82463225 2.项目-高性能TcpServ ...
- 学习 java netty (一) -- java nio
前言:近期在研究java netty这个网络框架,第一篇先介绍java的nio. java nio在jdk1.4引入,事实上也算比較早的了.主要引入非堵塞io和io多路复用.内部基于reactor模式 ...
- 高性能TcpServer(C#) - 1.网络通信协议
高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...
- 高性能TcpServer(C#) - 3.命令通道(处理:掉包,粘包,垃圾包)
高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...
随机推荐
- 神兽、佛祖保佑,代码全程无bug
''' ━━━━━━神兽出没━━━━━━ ┏┓ ┏┓ ┏┛┻━━━━━┛┻┓ ┃ ┃ ┃ ━ ┃ ┃ ┳┛ ┗┳ ┃ ┃ ┃ ┃ ┻ ┃ ┃ ┃ ┗━┓ ┏━┛ Code is far away fr ...
- 20191003 「HZOJ NOIP2019 Round #8」20191003模拟
综述 试题为常州集训2019SCDay2 得分\(100+30(0)+28\) 时之终结 问题描述 HZOJ1310 题解 构造题. 发现部分分有一档是 \(Y\) 是 \(2^x\) ,于是自然想到 ...
- C++中整型变量的存储大小和范围
一.代码查看 #include <iostream> #include <climits> using namespace std; int main(void) { cout ...
- Ztree + bootstarp-table 使用
Ztree + bootstarp-table 使用 一. Ztree 1.引入js/css文件 Ztree官网 <!--ztree--> <link rel="sty ...
- [LeetCode] 907. Sum of Subarray Minimums 子数组最小值之和
Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarra ...
- [LeetCode] 494. Target Sum 目标和
You are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now you have 2 symb ...
- [LeetCode] 457. Circular Array Loop 环形数组循环
You are given a circular array nums of positive and negative integers. If a number k at an index is ...
- bcrypt 加密算法
MD5 的特性 MD5 是一种加密算法,在调用这个算法的时候,提供一个密码的明文, 调用的结果,得到一个 32 位长度的密文: MD5 算法的特性:相同的字符串,如果多次调用 md5 算法,得到的结果 ...
- 解决SpringDataJpa实体类中属性顺序与数据库中生成字段顺序不一致的问题
一.在application.yml配置中添加数据库根据实体类自动创建数据库表的配置(这里数据库采用MySQL数据库) jpa: database: MYSQL show-sql: true #Hib ...
- torch_09_DCGAN_注意的细节
DCGAN github链接:https://github.com/darr/DCGAN DCGAN:1.在一次epoch中,如果第i批的i能够整除every_print,则打印到output文件中( ...