Java Socket编程及源码解析

Java Socket示例
ServerSocket
public class BioServer {
    private int port;
    private ExecutorService service = Executors.newFixedThreadPool(3);

    public BioServer(int port) {
        this.port = port;
    }

    public void start() {
        ServerSocket serverSocket = null;
        Socket socket = null;

        try {
            serverSocket = new ServerSocket(port);
            while (true) {
                socket = serverSocket.accept();
                service.submit(new ServerHandler(socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static class ServerHandler implements Runnable {

        private Socket socket;

        public ServerHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            BufferedReader reader = null;
            PrintWriter writer = null;

            try {
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                writer = new PrintWriter(socket.getOutputStream(), true);

                String threadName = Thread.currentThread().getName();
                String requestName = socket.getInetAddress().getHostName();
                String readerInfo = null;
                while (true) {
                    readerInfo = reader.readLine();
                    if (readerInfo == null) {
                        break;
                    }
                    System.out.println("接收到客户端消息:" + readerInfo + ",处理线程:" + threadName);
                    writer.println(requestName + " 你的请求已处理,处理线程:" + threadName);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    if (reader != null) {
                        reader.close();
                    }
                    if (writer != null) {
                        writer.close();
                    }
                    if (socket != null) {
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args){
        new BioServer(8080).start();
    }

}
Socket Client
public class BioClient {
    private static final String host = "127.0.0.1";
    private static final int port = 8080;

    public void connect(String host, int port) {
        Socket socket = null;
        BufferedReader reader = null;
        PrintWriter writer = null;

        try {
            socket = new Socket();
            socket.connect(new InetSocketAddress(host, port));
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            writer = new PrintWriter(socket.getOutputStream(), true);

            while (true) {
                writer.println("Hello Server, I am " + socket.getInetAddress());
                String response = reader.readLine();
                System.out.println("server return message : " + response);

                Thread.sleep(3000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (writer != null) {
                    writer.close();
                }
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args){
        new BioClient().connect(host, port);
    }
}
源码解析

Java Socket实现类继承关系,ServerSocket,Socket中都包含一个SocketImpl对象,SocketImpl中包含一个ServerSocket和一个Socket对象,默认SocksSocketImpl
这里写图片描述

Java API调用Socket绑定端口、监听、连接等都需要调用底层系统的Socket,这些操作在DualStackPlainSocketImpl中实现

void socketCreate(boolean stream) throws IOException {
    ……
    int newfd = socket0(stream, false /*v6 Only*/);
    fdAccess.set(fd, newfd);
}

void socketConnect(InetAddress address, int port, int timeout)
    throws IOException {
    int nativefd = checkAndReturnNativeFD();

    if (address == null)
        throw new NullPointerException("inet address argument is null.");

    int connectResult;
    if (timeout <= 0) {
        connectResult = connect0(nativefd, address, port);
    } else {
        configureBlocking(nativefd, false);
        try {
            connectResult = connect0(nativefd, address, port);
            if (connectResult == WOULDBLOCK) {
                waitForConnect(nativefd, timeout);
            }
        } finally {
            configureBlocking(nativefd, true);
        }
    }
    /*
     * We need to set the local port field. If bind was called
     * previous to the connect (by the client) then localport field
     * will already be set.
     */
    if (localport == 0)
        localport = localPort0(nativefd);
}

void socketBind(InetAddress address, int port) throws IOException {
    int nativefd = checkAndReturnNativeFD();

    if (address == null)
        throw new NullPointerException("inet address argument is null.");

    bind0(nativefd, address, port, exclusiveBind);
    if (port == 0) {
        localport = localPort0(nativefd);
    } else {
        localport = port;
    }

    this.address = address;
}

void socketListen(int backlog) throws IOException {
    int nativefd = checkAndReturnNativeFD();

    listen0(nativefd, backlog);
}

void socketAccept(SocketImpl s) throws IOException {
    int nativefd = checkAndReturnNativeFD();

    if (s == null)
        throw new NullPointerException("socket is null");

    int newfd = -1;
    InetSocketAddress[] isaa = new InetSocketAddress[1];
    if (timeout <= 0) {
        newfd = accept0(nativefd, isaa);
    } else {
        configureBlocking(nativefd, false);
        try {
            waitForNewConnection(nativefd, timeout);
            newfd = accept0(nativefd, isaa);
            if (newfd != -1) {
                configureBlocking(newfd, true);
            }
        } finally {
            configureBlocking(nativefd, true);
        }
    }
    /* Update (SocketImpl)s' fd */
    fdAccess.set(s.fd, newfd);
    /* Update socketImpls remote port, address and localport */
    InetSocketAddress isa = isaa[0];
    s.port = isa.getPort();
    s.address = isa.getAddress();
    s.localport = localport;
}
1. 实例化ServerSocket

ServerSocket(int port, int backlog, InetAddress bindAddr)

  • port:端口
  • backlog:ServerSocket有一个队列,存放还没有来得及处理的客户端Socket,这个队列的容量就是backlog的含义,默认是50
  • bindAddr:绑定地址
  • FileDescriptor
    一个打开的文件通过唯一的描述符进行引用,该描述符是打开文件的元数据到文件本身的映射。简单的讲,也就是有了Map结构,key是fd,value是文件的信息(包括物理地址、读取模式。。。。。)
    0 标准输入(stdin),1标准输出(stdout),2标准错误(stderr)

ServerSocket

public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
    setImpl();
    if (port < 0 || port > 0xFFFF)
        throw new IllegalArgumentException(
                   "Port value out of range: " + port);
    if (backlog < 1)
      backlog = 50;
    try {
        bind(new InetSocketAddress(bindAddr, port), backlog);
    } catch(SecurityException e) {
        close();
        throw e;
    } catch(IOException e) {
        close();
        throw e;
    }
}

//ServerSocket中有一个属性 private SocketImpl impl;
//抽象类SocketImpl中有一个Socket和ServerSocket
//父类PlainSocketImpl类中有个private AbstractPlainSocketImpl impl;真正调用Native系统socket0的实现

private void setImpl() {
    if (factory != null) {
        impl = factory.createSocketImpl();
        checkOldImpl();
    } else {
        //先执行父类PlainSocketImpl构造方法,设置impl = new DualStackPlainSocketImpl(exclusiveBind);
        impl = new SocksSocketImpl();
    }
    if (impl != null)
        impl.setServerSocket(this);
}

PlainSocketImpl(FileDescriptor fd) {
    if (useDualStackImpl) {
        impl = new DualStackPlainSocketImpl(fd, exclusiveBind);
    } else {
        impl = new TwoStacksPlainSocketImpl(fd, exclusiveBind);
    }
}

//绑定端口
public void bind(SocketAddress endpoint, int backlog) throws IOException {
……
    if (backlog < 1)
      backlog = 50;
    try {
      ……
        getImpl().bind(epoint.getAddress(), epoint.getPort());
        getImpl().listen(backlog);
        bound = true;
    }
     ……
}
SocketImpl getImpl() throws SocketException {
    if (!created)
        createImpl();
    return impl;
}

void createImpl() throws SocketException {
    if (impl == null)
        setImpl();
    try {
        //真正调用系统Socket的地方
        impl.create(true);
        created = true;
    } catch (IOException e) {
        throw new SocketException(e.getMessage());
    }
}

SocksSocketImpl

protected synchronized void create(boolean stream) throws IOException {
    //抽象类中实现
    impl.create(stream);
    // set fd to delegate's fd to be compatible with older releases
    this.fd = impl.fd;
}

//抽象类AbstractPlainSocketImpl

protected synchronized void create(boolean stream) throws IOException {
……
fd = new FileDescriptor();
socketCreate(true);
……
}
DualStackPlainSocketImpl

void socketCreate(boolean stream) throws IOException {
    if (fd == null)
        throw new SocketException("Socket closed");
    int newfd = socket0(stream, false /*v6 Only*/);
    fdAccess.set(fd, newfd);
}

void socketBind(InetAddress address, int port) throws IOException {
    ……
    bind0(nativefd, address, port, exclusiveBind);
  ……
}

void socketListen(int backlog) throws IOException {
    int nativefd = checkAndReturnNativeFD();
    listen0(nativefd, backlog);
}

ServerSocket接受连接accept方法

public Socket accept() throws IOException {
  ……
  //构造参数为null,构造方法中不执行任何操作
    Socket s = new Socket((SocketImpl) null);
    implAccept(s);
    return s;
}

protected final void implAccept(Socket s) throws IOException {
       SocketImpl si = null;
       try {
           if (s.impl == null)
           //调用Socket中的setImpl方法设置SocketImpl实现,操作和ServerSocket一致
             s.setImpl();
           else {
               s.impl.reset();
           }
           si = s.impl;
           s.impl = null;
           si.address = new InetAddress();
           si.fd = new FileDescriptor();
           //获取Socket实现,并调用accept方法,在父类PlainSocketImpl中委托给抽象类AbstractPlainSocketImpl中的impl实现,真正实现在DualStackPlainSocketImpl的方法socketAccept(SocketImpl s)中
           getImpl().accept(si);

……
   s.impl = si;
   s.postAccept();
}
  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值