Java|从操作系统层面分析 Java IO 演进之路( 四 )


package telnet;
import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandler.Sharable;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;import java.net.InetAddress;import java.util.Date;/** * Handles a server-side channel. */@Sharablepublic class TelnetServerHandler extends SimpleChannelInboundHandlerString{ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // Send greeting for a new connection. ctx.write(\"Welcome to \" + InetAddress.getLocalHost().getHostName() + \"!\\r\\"); ctx.write(\"It is \" + new Date() + \" now.\\r\\"); ctx.flush();@Override public void channelRead0(ChannelHandlerContext ctx String request) throws Exception { // Generate and write a response. String response; boolean close = false; if (request.isEmpty()) { response = \"Please type something.\\r\\";else if (\"bye\".equals(request.toLowerCase())) { response = \"Have a good day!\\r\\"; close = true;else { response = \"Did you say '\" + request + \"'?\\r\\";// We do not need to write a ChannelBuffer here. // We know the encoder inserted at TelnetPipelineFactory will do the conversion. ChannelFuture future = ctx.write(response); // Close the connection after sending 'Have a good day!' // if the client has sent 'bye'. if (close) { future.addListener(ChannelFutureListener.CLOSE);@Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush();@Override public void exceptionCaught(ChannelHandlerContext ctx Throwable cause) { cause.printStackTrace(); ctx.close();TelnetServerInitializer
package telnet;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelPipeline;import io.netty.channel.socket.SocketChannel;import io.netty.handler.codec.DelimiterBasedFrameDecoder;import io.netty.handler.codec.Delimiters;import io.netty.handler.codec.string.StringDecoder;import io.netty.handler.codec.string.StringEncoder;import io.netty.handler.ssl.SslContext;/** * Creates a newly configured {@link ChannelPipeline for a new channel. */public class TelnetServerInitializer extends ChannelInitializerSocketChannel{ private static final StringDecoder DECODER = new StringDecoder(); private static final StringEncoder ENCODER = new StringEncoder(); private static final TelnetServerHandler SERVER_HANDLER = new TelnetServerHandler(); private final SslContext sslCtx; public TelnetServerInitializer(SslContext sslCtx) { this.sslCtx = sslCtx;@Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); if (sslCtx != null) { pipeline.addLast(sslCtx.newHandler(ch.alloc()));// Add the text line codec combination first pipeline.addLast(new DelimiterBasedFrameDecoder(8192 Delimiters.lineDelimiter())); // the encoder and decoder are static as these are sharable pipeline.addLast(DECODER); pipeline.addLast(ENCODER); // and then business logic. pipeline.addLast(SERVER_HANDLER);2 启动后的系统调用
主线程(23109)
## 256无实际作用 , 这里只为了兼容旧版kernel apiepoll_create(256) = 7epoll_ctl(7 EPOLL_CTL_ADD 5 {EPOLLIN {u32=5 u64=5477705356928876549) = 0epoll_create(256) = 10epoll_ctl(10 EPOLL_CTL_ADD 8 {EPOLLIN {u32=8 u64=17041805914081853448) = 0epoll_create(256) = 13epoll_ctl(13 EPOLL_CTL_ADD 11 {EPOLLIN {u32=11 u64=17042151607409573899) = 0epoll_create(256) = 16epoll_ctl(16 EPOLL_CTL_ADD 14 {EPOLLIN {u32=14 u64=17042497300737294350) = 0epoll_create(256) = 19epoll_ctl(19 EPOLL_CTL_ADD 17 {EPOLLIN {u32=17 u64=17042561450368827409) = 0epoll_create(256) = 10socket(AF_INET SOCK_STREAM IPPROTO_IP) = 20clone(child_stack=0x7fc3c509afb0 flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID parent_tidptr=0x7fc3c509b9d0 tls=0x7fc3c509b700 child_tidptr=0x7fc3c509b9d0) = 23130 概括为:
向OS新建socket , 并开启clone boss线程23130 。 为BOSS创建了一个epoll(论证参见下面“boss”) , 每个worker创建一个epoll数据结构(本质上是在kernel内存区创建了一个数据结构 , 用于后续监听) 。 创建boss线程监听的socket(本质上在kernel中创建一个数据结构) 。 boss(23130)