Java netty 客户端无法向服务器发送消息,但 telnet 可以服务器
Java netty client cannot send message to server, but telnet to sever ok
我正在学习 Java Netty 通过套接字 7000 制作非常简单的客户端-服务器。服务器正在 运行ning 并且它将回显从客户端收到的消息。如果我使用 telnet localhost 7000 并将消息发送到服务器并接收回显消息,它就会工作。
但是,对于 Java Netty 客户端,它不起作用。服务器什么也没收到,客户端什么也没发送?当我试图向控制台添加一些内容时。
这里是这个例子的类:
客户
public final class EchoClient {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new LoggingHandler(LogLevel.TRACE),
new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()),
new StringEncoder(),
new StringDecoder(),
new EchoClientHandler());
}
});
// Start the connection attempt.
bootstrap.connect("localhost", 7000).sync().channel().closeFuture().sync();
System.out.println("Message sent successfully.");
} finally {
group.shutdownGracefully();
}
}
}
public class EchoClientHandler extends SimpleChannelInboundHandler<String> {
/**
* Constructor for the class
*
* @param message the message you want to transmit
*/
public EchoClientHandler() {
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String message = "message from client.";
System.out.println("Sending message: " + message);
ctx.write(message);
ctx.flush();
ctx.close();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.out.println("Error caught in the communication service: " + cause);
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Received message: " + msg);
}
}
服务器
public final class EchoServer {
static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "7000"));
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.TRACE))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new LoggingHandler(LogLevel.TRACE),
new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()),
new StringEncoder(),
new StringDecoder(),
new EchoServerHandler());
}
});
System.out.println("Server is listening on port 7000.");
// Start the server.
ChannelFuture channelFuture = serverBootstrap.bind("localhost", 7000).sync();
// Wait until the server socket is closed.
channelFuture.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
public class EchoServerHandler extends SimpleChannelInboundHandler<String> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String message = "message from server.";
System.out.println("Sending message: " + message);
ctx.write(message);
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
System.out.println("Error in receiving message.");
cause.printStackTrace();
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception {
System.out.println("Received message: " + message);
ctx.write(message);
ctx.flush();
//ctx.close();
}
}
所以当我运行 EchoServer,然后我运行 EchoClient,EchoClient 的输出是
Sending message: message from client.
Message sent successfully.
Then application stopped.
EchoServer 的输出是
Sending message: message from server.
比较客户端和 telnet 之间的协议(使用 LoggingHandler 或 Wireshark),如果这样做,您会注意到这 2 个协议之间有 1 个主要区别。
不同之处在于,您发送的邮件末尾没有换行符,而 telnet 有。
解决这个问题真的很简单,只需在消息末尾添加一个新的换行符,或者编写一个新的处理程序来自动为您执行此操作。
ctx.write(message + "\n");
您可以做的另一个改进是调用 writeAndFlush
而不是先写入,然后刷新,这也可以防止您在编码时被打断时错过对其他方法的调用。
在您的代码中,DelimiterBasedFrameDecoder
处理程序出现在 decoder/encoder 之前。因此,如果传输的消息没有预期的分隔符(例如本例中的新行),client/server 将继续等待并认为消息仍在传输。因此,有两种可能的方法可以解决您的问题。
- 在客户端和服务器中删除
new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter())
- 每次通过频道发送消息时,请添加新的行分隔符。否则,无法从另一端解码消息。请在下面找到示例代码
EchoClientHandlerclass
public class EchoClientHandler extends SimpleChannelInboundHandler<String> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String message = "message from client.";
System.out.println("Sending message: " + message);
ctx.writeAndFlush(message + System.lineSeparator());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.out.println("Error caught in the communication service: " + cause);
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Received message: " + msg);
}
}
EchoServerHandlerclass
public class EchoServerHandler extends SimpleChannelInboundHandler<String> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String message = "message from server.";
System.out.println("Sending message: " + message);
ctx.writeAndFlush(message + System.lineSeparator());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.out.println("Error in receiving message.");
cause.printStackTrace();
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception {
System.out.println("Received message: " + message);
ctx.writeAndFlush(message + System.lineSeparator());
}
}
来自服务器的输出
Server is listening on port 7000.
Sending message: message from server.
Received message: message from client.
来自客户端的输出
Sending message: message from client.
Received message: message from server.
Received message: message from client.
我正在学习 Java Netty 通过套接字 7000 制作非常简单的客户端-服务器。服务器正在 运行ning 并且它将回显从客户端收到的消息。如果我使用 telnet localhost 7000 并将消息发送到服务器并接收回显消息,它就会工作。
但是,对于 Java Netty 客户端,它不起作用。服务器什么也没收到,客户端什么也没发送?当我试图向控制台添加一些内容时。
这里是这个例子的类:
客户
public final class EchoClient {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new LoggingHandler(LogLevel.TRACE),
new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()),
new StringEncoder(),
new StringDecoder(),
new EchoClientHandler());
}
});
// Start the connection attempt.
bootstrap.connect("localhost", 7000).sync().channel().closeFuture().sync();
System.out.println("Message sent successfully.");
} finally {
group.shutdownGracefully();
}
}
}
public class EchoClientHandler extends SimpleChannelInboundHandler<String> {
/**
* Constructor for the class
*
* @param message the message you want to transmit
*/
public EchoClientHandler() {
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String message = "message from client.";
System.out.println("Sending message: " + message);
ctx.write(message);
ctx.flush();
ctx.close();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.out.println("Error caught in the communication service: " + cause);
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Received message: " + msg);
}
}
服务器
public final class EchoServer {
static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "7000"));
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.TRACE))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new LoggingHandler(LogLevel.TRACE),
new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()),
new StringEncoder(),
new StringDecoder(),
new EchoServerHandler());
}
});
System.out.println("Server is listening on port 7000.");
// Start the server.
ChannelFuture channelFuture = serverBootstrap.bind("localhost", 7000).sync();
// Wait until the server socket is closed.
channelFuture.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
public class EchoServerHandler extends SimpleChannelInboundHandler<String> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String message = "message from server.";
System.out.println("Sending message: " + message);
ctx.write(message);
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
System.out.println("Error in receiving message.");
cause.printStackTrace();
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception {
System.out.println("Received message: " + message);
ctx.write(message);
ctx.flush();
//ctx.close();
}
}
所以当我运行 EchoServer,然后我运行 EchoClient,EchoClient 的输出是
Sending message: message from client.
Message sent successfully.
Then application stopped.
EchoServer 的输出是
Sending message: message from server.
比较客户端和 telnet 之间的协议(使用 LoggingHandler 或 Wireshark),如果这样做,您会注意到这 2 个协议之间有 1 个主要区别。
不同之处在于,您发送的邮件末尾没有换行符,而 telnet 有。
解决这个问题真的很简单,只需在消息末尾添加一个新的换行符,或者编写一个新的处理程序来自动为您执行此操作。
ctx.write(message + "\n");
您可以做的另一个改进是调用 writeAndFlush
而不是先写入,然后刷新,这也可以防止您在编码时被打断时错过对其他方法的调用。
在您的代码中,DelimiterBasedFrameDecoder
处理程序出现在 decoder/encoder 之前。因此,如果传输的消息没有预期的分隔符(例如本例中的新行),client/server 将继续等待并认为消息仍在传输。因此,有两种可能的方法可以解决您的问题。
- 在客户端和服务器中删除
new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter())
- 每次通过频道发送消息时,请添加新的行分隔符。否则,无法从另一端解码消息。请在下面找到示例代码
EchoClientHandlerclass
public class EchoClientHandler extends SimpleChannelInboundHandler<String> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String message = "message from client.";
System.out.println("Sending message: " + message);
ctx.writeAndFlush(message + System.lineSeparator());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.out.println("Error caught in the communication service: " + cause);
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Received message: " + msg);
}
}
EchoServerHandlerclass
public class EchoServerHandler extends SimpleChannelInboundHandler<String> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String message = "message from server.";
System.out.println("Sending message: " + message);
ctx.writeAndFlush(message + System.lineSeparator());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.out.println("Error in receiving message.");
cause.printStackTrace();
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception {
System.out.println("Received message: " + message);
ctx.writeAndFlush(message + System.lineSeparator());
}
}
来自服务器的输出
Server is listening on port 7000.
Sending message: message from server.
Received message: message from client.
来自客户端的输出
Sending message: message from client.
Received message: message from server.
Received message: message from client.