La dernière fois, j'ai essayé de créer un chemin de transfert TCP / IP + NIO / BIO en utilisant des bibliothèques telles que webSocket et SocketChannel, mais j'ai trouvé que le code devenait assez compliqué. Cette fois, je vais essayer de réaliser à nouveau un serveur en utilisant Netty.
En termes simples, Netty est un framework pour développer des applications qui communiquent de manière asynchrone. Par rapport au traitement NIO réalisé par SocketChannel, il n'est plus nécessaire d'exploiter directement les API de basse couche (select (), read (), etc.), et il est caché côté Netty.
Tout d'abord, je republierai la précédente implémentation NIO sur ServerSocket Channel.
➀ Créez un ServerSocketChannel et écoutez l'accès côté client
public class ChannelServer {
public static void main(String[] args) throws IOException {
// I/Préparer un pool de threads pour traiter les requêtes O
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 10, 1000, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(100));
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(1234));
while (true) {
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel != null) {
//Validez la demande dans le pool de threads
executor.submit(new ChannelServerThread(socketChannel));
}
}
}
}
② Thread pour traiter la demande
public class ChannelServerThread implements Runnable {
private SocketChannel socketChannel;
private String remoteName;
public ChannelServerThread(SocketChannel socketChannel) throws IOException {
this.socketChannel = socketChannel;
this.remoteName = socketChannel.getRemoteAddress().toString();
System.out.println("client:" + remoteName + " access successfully!");
}
// I/Gérer la demande O
@Override
public void run() {
ByteBuffer buffer = ByteBuffer.allocate(1024);
ByteBuffer sizeBuffer = ByteBuffer.allocate(4);
StringBuilder sb = new StringBuilder();
byte b[];
//Lire les données et la longueur de socketChannel et sortie vers la sortie standard
while(true) {
try {
sizeBuffer.clear();
int read = socketChannel.read(sizeBuffer);
if (read != -1) {
sb.setLength(0);
sizeBuffer.flip();
int size = sizeBuffer.getInt();
int readCount = 0;
b = new byte[1024];
while (readCount < size) {
buffer.clear();
read = socketChannel.read(buffer);
if (read != -1) {
readCount += read;
buffer.flip();
int index = 0 ;
while(buffer.hasRemaining()) {
b[index++] = buffer.get();
if (index >= b.length) {
index = 0;
sb.append(new String(b,"UTF-8"));
}
}
if (index > 0) {
sb.append(new String(b,"UTF-8"));
}
}
}
System.out.println(remoteName + ":" + sb.toString());
}
} catch (Exception e) {
System.out.println(remoteName + "access colsed");
try {
socketChannel.close();
} catch (IOException ex) {
}
break;
}
}
}
}
➀ Traitement en attente d'accès côté client
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap sb = new ServerBootstrap();
//Liaison de pool de threads
sb.group(group)
.channel(NioServerSocketChannel.class)
//Liaison de numéro de port
.localAddress(this.port)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
System.out.println("connected...; Client:" + ch.remoteAddress());
ch.pipeline().addLast(new EchoServerHandler());
}
});
//Liaison asynchrone du serveur
ChannelFuture cf = sb.bind().sync();
System.out.println(EchoServer.class + " started and listen on " + cf.channel().localAddress());
//Fermer le canal du serveur
cf.channel().closeFuture().sync();
} finally {
//Dissocier le pool de threads
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
//entrée
new EchoServer(66666).start();
}
}
② Celui qui traite la demande
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("server channelRead...; received:" + msg);
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("server channelReadComplete..");
//WriteAndFlush dans un tampon vide,Fermer la connexion
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("server occur exception:" + cause.getMessage());
cause.printStackTrace();
ctx.close();
}
}
** La quantité de code a été considérablement réduite. ** ** Cela permet de masquer les API telles que les opérations read () et Buffer du côté Netty et de fournir une API de couche supérieure pratique. Par exemple, la méthode channelRead () de la classe EchoServerHandler: lorsque les données du côté client sont reçues, elles sont converties en interne en String, cette méthode est donc appelée.
Cette fois, j'ai essayé d'implémenter le serveur en utilisant Netty. Je présenterai la coopération avec le client la prochaine fois.
Recommended Posts