netty学习必备基础

1.IO第一阶段,BIO,阻塞式IO

  服务器端代码:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public abstract class Server {

    public  static int DEFAULT_HOSTS=7778;

    public static ServerSocket serverSocket;

    public static void start() throws IOException{
        start(DEFAULT_HOSTS);
    }

    private static void start(int defaultHosts)  throws IOException{
        if (serverSocket!=null) return;
           try {
               serverSocket = new ServerSocket(defaultHosts);
               System.out.println(("客户端已经启动" + defaultHosts));
               Socket socket=serverSocket.accept();
               new Thread(new ServerHandler(socket)).start();

           }finally {
               serverSocket.close();

           }
       }

    public static void main(String[] args) {

        Server server=new Server() {
            @Override
            public int hashCode() {
                return super.hashCode();
            }
        };
        try {
            server.start(7778);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

客户端代码:

import java.io.*;
import java.net.Socket;

public class Client {
    private  String ip="127.0.0.1";
    private  static final  int port=7778;
    private Socket socket=null;
    PrintWriter printWriter=null;
    BufferedReader bufferedReader=null;
    public void sed(String s){
        try {
            socket=new Socket(ip,port);
            bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));

            printWriter = new PrintWriter(socket.getOutputStream(), true);
            printWriter.println(s);
            String s1 ;
            while (true){
                if((s1 = bufferedReader.readLine())!=null)
                System.out.println(s1);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Client client=new Client();

        client.sed("start--");
    }

核心源码:

/**
 * Accepts connections.
 * @param s the connection
 */
protected void accept(SocketImpl s) throws IOException {
    acquireFD();
    try {
        socketAccept(s);
    } finally {
        releaseFD();
    }
}

NIO阶段,同步非阻塞IO:

客户端输入消息:

public class NioClient {
    public static void main(String[] args) {
        InetSocketAddress address=new InetSocketAddress("127.0.0.1",7778);

        SocketChannel socketChannel=null;

        ByteBuffer byteBuffer=ByteBuffer.allocate(1024);

        try {
            socketChannel= SocketChannel.open();

            socketChannel.connect(address);
            while (true){
                byte[] bytes=new byte[1024];
                System.in.read(bytes);
                byteBuffer.put(bytes);
                byteBuffer.flip();
                socketChannel.write(byteBuffer);
                byteBuffer.clear();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }


    }
}

服务器端代码:

 

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;

public class SeverHadler implements Runnable{


          Selector selector=null;
         InetSocketAddress inetSocketAddress;
         //2 建立缓冲区
         private ByteBuffer readBuf = ByteBuffer.allocate(1024);
         //3
         private ByteBuffer writeBuf = ByteBuffer.allocate(1024);
         public SeverHadler(int port){
             this.inetSocketAddress=new InetSocketAddress(port);
         }
         @Override
         public void run() {
             Charset charset=Charset.forName("UTF-8");


             Random rnd=new Random();

             try {
                 selector=Selector.open();
                 ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
                 serverSocketChannel.configureBlocking(false);
                 serverSocketChannel.bind(inetSocketAddress);
                 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
             } catch (IOException e) {
                 e.printStackTrace();
             }

             while (!Thread.currentThread().isInterrupted()){
                 try {
                     int select = selector.select();
                     if (select==0){
                         continue;
                     }
                     Set<SelectionKey> keySet=selector.selectedKeys();
                     Iterator<SelectionKey> iterator = keySet.iterator();
                     SelectionKey selectionKey=null;
                     while (iterator.hasNext()){
                         SelectionKey next = iterator.next();
                         iterator.remove();

                         if (next.isValid()){
                             if(next.isAcceptable()){
                                 this.accept(next);
                             }
                             //8 如果为可读状态
                             if(next.isReadable()){
                                 this.read(next);
                             }
                             //9 写数据
                             if(next.isWritable()){
                                 //this.write(key); //ssc
                             }
                         }
                     }
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
         }

    private void write(SelectionKey key){
        //ServerSocketChannel ssc =  (ServerSocketChannel) key.channel();
        //ssc.register(this.seletor, SelectionKey.OP_WRITE);
    }

    private void read(SelectionKey key) {
        try {
            //1 清空缓冲区旧的数据
            this.readBuf.clear();
            //2 获取之前注册的socket通道对象
            SocketChannel sc = (SocketChannel) key.channel();
            //3 读取数据
            int count = sc.read(this.readBuf);
            //4 如果没有数据
            if(count == -1){
                key.channel().close();
                key.cancel();
                return;
            }
            //5 有数据则进行读取 读取之前需要进行复位方法(把position 和limit进行复位)
            this.readBuf.flip();
            //6 根据缓冲区的数据长度创建相应大小的byte数组,接收缓冲区的数据
            byte[] bytes = new byte[this.readBuf.remaining()];
            //7 接收缓冲区数据
            this.readBuf.get(bytes);
            //8 打印结果
            String body = new String(bytes).trim();
            System.out.println("Server : " + body);

            // 9..可以写回给客户端数据

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void accept(SelectionKey key) {
        try {
            //1 获取服务通道
            ServerSocketChannel ssc =  (ServerSocketChannel) key.channel();
            //2 执行阻塞方法
            SocketChannel sc = ssc.accept();
            //3 设置阻塞模式
            sc.configureBlocking(false);
            //4 注册到多路复用器上,并设置读取标识
            sc.register(this.selector, SelectionKey.OP_READ);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

核心源码:

open时候实际上是返回了一个文件描述

static FileDescriptor socket(boolean var0) throws IOException {
    return socket(UNSPEC, var0);
}

static FileDescriptor socket(ProtocolFamily var0, boolean var1) throws IOException {
    boolean var2 = isIPv6Available() && var0 != StandardProtocolFamily.INET;
    return IOUtil.newFD(socket0(var2, var1, false, fastLoopback));
}

connect时先声明一个读锁一个写锁,解答一个疑惑为什么需要两个锁分别为读和写。可以理解为操作系统里面两辆车过桥的问题,两个车,一个桥,如何让桥两边的车通过。

this.begin();
    var9 = this.stateLock;
    synchronized(this.stateLock) {
        if (!this.isOpen()) {
            boolean var10 = false;
            return var10; }
        if (this.localAddress == null) {
            NetHooks.beforeTcpConnect(this.fd, var5.getAddress(), var5.getPort());
        }
        this.readerThread = NativeThread.current();
    }
    do {
        InetAddress var31 = var5.getAddress();
        if (var31.isAnyLocalAddress()) {
            var31 = InetAddress.getLocalHost();
        }
        //用了Net进行连接
        var8 = Net.connect(this.fd, var31, var5.getPort());
    } while(var8 == -3 && this.isOpen());//循环的
} finally {
    this.readerCleanup();
    this.end(var8 > 0 || var8 == -2);
    assert IOStatus.check(var8);
}

 

synchronized(this.stateLock) {
    if (!this.isOpen()) {
        var5 = 0;
        var20 = false;
        break label310;
    }

    this.writerThread = NativeThread.current();
}

do {
//IO写入
    var3 = IOUtil.write(this.fd, var1, -1L, nd);
} while(var3 == -3 && this.isOpen());

最终调用:

private static int writeFromNativeBuffer(FileDescriptor var0, ByteBuffer var1, long var2, NativeDispatcher var4) throws IOException {
    int var5 = var1.position();
    int var6 = var1.limit();

    assert var5 <= var6;

    int var7 = var5 <= var6 ? var6 - var5 : 0;
    boolean var8 = false;
    if (var7 == 0) {
        return 0;
    } else {
        int var9;
        if (var2 != -1L) {
          //最终写入
            var9 = var4.pwrite(var0, ((DirectBuffer)var1).address() + (long)var5, var7, var2);
        } else {
            var9 = var4.write(var0, ((DirectBuffer)var1).address() + (long)var5, var7);
        }

        if (var9 > 0) {
            var1.position(var5 + var9);
        }

        return var9;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值