import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class NettyClient {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new ClientHandler());
}
});
ChannelFuture future = bootstrap.connect("localhost", 8080).sync();
Channel channel = future.channel();
String request = "Hello, Server!";
channel.writeAndFlush(request);
// 等待响应
ChannelFuture responseFuture = channel.read();
responseFuture.addListener((ChannelFutureListener) future1 -> {
if (future1.isSuccess()) {
String response = (String) future1.channel().readInbound();
System.out.println("Received response: " + response);
} else {
future1.cause().printStackTrace();
}
});
channel.closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
static class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
// 处理响应
System.out.println("Client received: " + msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
}
关于使用 Netty 4 实现服务发送数据之后等待返回结果,通常可以通过以下几种方式来实现:
1. **使用 ChannelFuture 和 ChannelFutureListener**:
- 当你发送数据后,可以得到一个 `ChannelFuture` 对象,这个对象代表了异步操作的结果。你可以添加一个 `ChannelFutureListener` 来监听操作完成后的事件。
2. **使用 Promise 和 Future**:
- 创建一个 `DefaultPromise` 或 `DefaultFuture`,然后在接收到响应时设置其结果。这样可以在发送请求的地方通过 `Future` 的 `get()` 方法来阻塞等待结果,或者使用 `addListener` 来异步处理结果。
3. **使用自定义协议和消息ID**:
- 在发送请求时,为每个请求分配一个唯一的ID,并将这个ID与一个 `Promise` 关联起来。当接收到响应时,根据响应中的ID找到对应的 `Promise` 并设置结果。
4. **使用 RPC 框架**:
- 如果应用场景复杂,可以考虑使用基于 Netty 的 RPC 框架,如 Dubbo 或 gRPC。这些框架已经实现了请求-响应模式,可以简化开发过程。
以下是一个简单的示例,展示了如何使用 `ChannelFuture` 和 `ChannelFutureListener` 来实现发送数据并等待响应:
```java
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class NettyClient {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new ClientHandler());
}
});
ChannelFuture future = bootstrap.connect("localhost", 8080).sync();
Channel channel = future.channel();
String request = "Hello, Server!";
channel.writeAndFlush(request);
// 等待响应
ChannelFuture responseFuture = channel.read();
responseFuture.addListener((ChannelFutureListener) future1 -> {
if (future1.isSuccess()) {
String response = (String) future1.channel().readInbound();
System.out.println("Received response: " + response);
} else {
future1.cause().printStackTrace();
}
});
channel.closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
static class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
// 处理响应
System.out.println("Client received: " + msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
}
```
在这个示例中,客户端发送一个字符串请求到服务器,并通过 `ChannelFutureListener` 来处理服务器的响应。请注意,这只是一个简单的演示,实际应用中可能需要更复杂的逻辑来处理不同的消息类型和错误情况。