使用telnet连接netty:发送定长字符串
//1、启动Server,输入telnet命令:telnet localhost 8088
public class NettyServer {
private int port=8088;
public static void main(String[] args) {
NettyServer server = new NettyServer();
server.run();
}
void run() {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
//客户端发送给服务端:hello server,im a client这符串,
//该字符串占用24字节,所以在服务端channelpipeline里面添加一个长度
//为24的定长解码器和二进制转换为string的解码器
p.addLast(new FixedLengthFrameDecoder(24));
p.addLast(new StringDecoder()); //与SimpleChannelInboundHandler<String> 泛型对应
p.addLast(new ServerHandler2());
}}
).option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
}catch(Exception e) {
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
public class ServerHandler2 extends SimpleChannelInboundHandler<String> {
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("from client: "+msg + msg.getClass());
String sendContent="hello client,im server";
ByteBuf sendMsg = Unpooled.buffer(sendContent.length());
sendMsg.writeBytes(sendContent.getBytes());
ctx.writeAndFlush(Unpooled.copiedBuffer(sendMsg));
}
}
客户端:
public class NettyClient {
private String host="localhost";
private int port = 8088;
public static void main(String[] args) {
new NettyClient().run();
}
public void run() {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
//.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch)throws Exception {
ChannelPipeline p=ch.pipeline();
//服务端发送:hello client,im server字符串,占用22字节
p.addLast(new FixedLengthFrameDecoder(22)); //缓冲区达到22字节,才写入通道
p.addLast(new StringDecoder());
p.addLast("handler",new ClientHandler2());
}
});
ChannelFuture f = b.connect(host,port).sync();
f.channel().closeFuture().sync();
}catch(Exception e) {
e.printStackTrace();
}
finally {
try {
group.shutdownGracefully().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ClientHandler2 extends SimpleChannelInboundHandler<String>{
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("client channelRead0.."+msg);
}
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("client channelActive..");
ctx.writeAndFlush(Unpooled.copiedBuffer("hello server,im a client".getBytes()));
}
}
分享到:
相关推荐
分隔符解码器适用于以特定字符或字符串分隔的帧,而定长解码器则适用于数据帧长度固定的情况。理解并灵活运用这两个解码器,能够帮助我们更高效地构建网络通信系统。 综上所述,Netty的分隔符解码器和定长解码器是...
在客户端,我们发送了一个比较长的字符串,如果服务端收到的消息是一条,那么就是对的,如果是多条,那么就有问题了。 解决粘包和拆包问题需要根据实际情况选择合适的方法,Netty 提供了多种解码器来帮助我们解决这...
然而,不同开发团队或开发者可能选用不同的工具包,如Netty、Spring等,这可能导致代码中存在不一致的字符串处理方式,增加了维护的复杂性。`commons-lang3`由于其全面的功能和广泛的适用性,成为了推荐的通用工具包...
StringDecoder 是 Netty 提供的一种编解码器,用于将字符串编码成字节码,以便于传输。 七、结论 TCP 粘包/拆包是 TCP 协议中的一种常见问题,可能会导致数据传输不正确。 Netty 提供了多种解决 TCP 粘包/拆包问题...
协议比较简单,所有的消息都一个Json字符串,格式如下: head | body | extend head作为头部,用int类型存储,4个字节; body 消息的有效载体,用string类型存储,长度无限度; extend 协议的扩展字段,用map类型...
Netty 提供了许多预定义的编码解码器,如`StringDecoder`和`StringEncoder`,用于将字符串数据在字节和对象之间转换。用户也可以自定义编码解码器来处理特定格式的数据。 8. **心跳机制**: 在长时间无数据传输的...
// 在这里处理固定长度的字节数组,例如将其转换为字符串或其他格式 byte[] data = new byte[in.readableBytes()]; in.getBytes(in.readerIndex(), data); // 执行业务逻辑 processData(data); } finally { ...
- 可以通过 `lrs_set_receive_option(EndMarker, StringTerminator, "\r\n")` 设置特定的字符串作为数据接收的结束标志。 - 例如,当数据以 `\r\n` 结尾时,LoadRunner 将会在接收到这个字符串后停止接收。 3. **...
- 由于 `new String("abc")` 创建的对象是在堆内存中,而字符串常量 `"abc"` 是在字符串常量池中,两者不相等。 2. **s2 == s3** 为 `true`。 - 假设 `s2` 为 `new String("abc").intern()` 的结果,`s3` 为 `"abc...
1. **#{} 和 ${} 区别**:#{} 是预编译处理,${} 是字符串替换,在动态 SQL 中为不同的情况选取不同的列名或表名。 2. **映射绑定**:MyBatis 使用接口绑定,将接口方法与 SQL 语句进行映射。 3. **动态 SQL**:通过...
6. **#{}与${}区别**:#{}是预编译处理,可防止SQL注入,而${}是字符串替换,存在SQL注入的风险。 7. **属性名和字段名不一致**:可以通过在实体类字段上使用`@TableField`注解或在映射文件中使用别名来解决。 8. ...
- **${}**:字符串替换,存在SQL注入的风险。 #### 7、当实体类中的属性名和表中的字段名不一样,怎么办? 可以通过`resultMap`中的`<result>`标签指定字段与属性之间的映射关系,也可以使用`@Results`注解来定义...