Beim letzten Mal habe ich versucht, mithilfe von Bibliotheken wie webSocket und SocketChannel einen TCP / IP + NIO / BIO-Übertragungspfad zu erstellen, aber ich habe festgestellt, dass der Code ziemlich kompliziert wurde. Dieses Mal werde ich versuchen, einen Server mit Netty erneut zu realisieren.
Einfach ausgedrückt ist Netty ein Framework für die Entwicklung von Anwendungen, die asynchron kommunizieren. Im Vergleich zur von SocketChannel realisierten NIO-Verarbeitung ist es nicht mehr erforderlich, Low-Layer-APIs (select (), read () usw.) direkt zu betreiben, und sie ist auf der Netty-Seite verborgen.
Zuerst werde ich die vorherige [NIO-Implementierung auf ServerSocket Channel] erneut veröffentlichen (https://qiita.com/haoyu_ma/items/bec7a50def5c18a0e1d2).
➀ Erstellen Sie einen ServerSocketChannel und warten Sie auf den clientseitigen Zugriff
public class ChannelServer {
public static void main(String[] args) throws IOException {
// I/Bereiten Sie einen Thread-Pool vor, um O-Anforderungen zu verarbeiten
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) {
//Übertragen Sie die Anforderung in den Thread-Pool
executor.submit(new ChannelServerThread(socketChannel));
}
}
}
}
② Thread zur Bearbeitung der Anfrage
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/O-Anfrage bearbeiten
@Override
public void run() {
ByteBuffer buffer = ByteBuffer.allocate(1024);
ByteBuffer sizeBuffer = ByteBuffer.allocate(4);
StringBuilder sb = new StringBuilder();
byte b[];
//Lesen Sie Daten und Länge von socketChannel und geben Sie sie in die Standardausgabe aus
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;
}
}
}
}
➀ Verarbeitung, die auf den Zugriff auf der Clientseite wartet
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();
//Thread-Pool-Bindung
sb.group(group)
.channel(NioServerSocketChannel.class)
//Portnummernbindung
.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());
}
});
//Asynchrone Bindung des Servers
ChannelFuture cf = sb.bind().sync();
System.out.println(EchoServer.class + " started and listen on " + cf.channel().localAddress());
//Serverkanal schließen
cf.channel().closeFuture().sync();
} finally {
//Thread-Pool aufheben
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
//Eingang
new EchoServer(66666).start();
}
}
② Derjenige, der die Anfrage bearbeitet
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 im leeren Puffer,Schließen Sie die Verbindung
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();
}
}
** Die Menge an Code wurde stark reduziert. ** ** ** Dies dient dazu, APIs wie read () und Buffer-Operationen von der Netty-Seite auszublenden und eine praktische High-Layer-API bereitzustellen. Beispiel: die channelRead () -Methode der EchoServerHandler-Klasse: Wenn Daten von der Clientseite empfangen werden, werden sie intern in einen String konvertiert, sodass diese Methode aufgerufen wird.
Diesmal habe ich versucht, den Server mit Netty zu implementieren. Ich werde das nächste Mal die Zusammenarbeit mit der Kundenseite vorstellen.