I/O复习(三)——Java Network

Java Network

InetAddress

java.net.InetAddress类是Java对IP地址的高层表示。大多数其他网络类都要用到这个类,包括Socket、ServerSocket、URL、DatagramSocket、DatagramPacket等。一般地讲,它包括一个主机名和一个IP地址。

InetAddress address = InetAddress.getByName("www.baidu.com");

这段代码会建立与本地DNS服务器的一个连接,来查找名字和数字地址。
DNS的查找的开销可能相当大,所以InetAddress类会缓存查找的结果。
是线程安全的。

127.0.0.1是本地回送地址。
224.0.0.0到239.255.255.255范围内的IPv4地址是组播地址,可以同时发送到多个订购的主机。

可达性

public boolean isReachable(int timeout) throws IOException
public boolean isReachable(NetworkInterface interface,int ttl,int timeout) throws IOException

InetAddress类会缓存请求过的地址。如果再次请求相同的地址,它可以从缓存中获取,这比从DNS获取要快的多。

Object方法

如果两个InetAddress对象有相同的地址,就会有相同的散列码,即使它们的主机名有所不同。
如果一个对象本身是InetAddress类的实例,而且与一个InetAddress对象有相同的IP地址,只有此时才会与该InetAddress对象相等,并不要求两个对象有相同的主机名。

NetworkInterface

NetworkInterface类表示一个本地IP地址。
NetworkInterface类提供了一些方法可以枚举所有的本地地址(而不考虑接口),并由它们创建InetAddress对象,然后这些InetAddress对象可用于创建socket、服务器socket等。

示例代码

import java.net.InetAddress;
import java.net.UnknownHostException;

public class MyAddress {
    public static void main(String[] args) throws UnknownHostException {
        try {
            InetAddress address = InetAddress.getLocalHost();
            System.out.println(address);
        } catch (UnknownHostException e) {
            System.out.println("Could not find this computer's address.");
        }
        InetAddress address = InetAddress.getByName("www.sina.com");
        byte[] addresses = address.getAddress();
        if (addresses.length == 4) {
            System.out.println("4");
        } else if (addresses.length == 16) {
            System.out.println("16");
        } else {
            System.out.println("-1");
        }
    }
}

import java.net.InetAddress;
import java.net.UnknownHostException;

public class IPCharacteristics {
    public static void main(String[] args) {
        try {
            InetAddress address = InetAddress.getByName(args[0]);
            // 通配地址
            if (address.isAnyLocalAddress()) {
                System.out.println(address + " is a wildcard address.");
            }
            // 回送地址
            if (address.isLoopbackAddress()) {
                System.out.println(address + " is loopback address.");
            }
            // 连接本地地址
            if (address.isLinkLocalAddress()) {
                System.out.println(address + " is a link-local address.");
            } else if (address.isSiteLocalAddress()) {
                System.out.println(address + " is a site-local address.");
            } else {
                System.out.println(address + " is a global address.");
            }

            //IP组播地址
            if (address.isMulticastAddress()) {
                // 多播地址是否具有全局范围的使用程序
                if (address.isMCGlobal()) {
                    System.out.println(address + " is a global multicast address.");
                } else if (address.isMCOrgLocal()) { // 组播地址是否具有节点范围
                    System.out.println(address + " is an organization wide multicast address.");
                } else if (address.isMCSiteLocal()) { // 多播地址是否具有站点范围的实用程序
                    System.out.println(address + " is a site wide multicast address.");
                } else if (address.isMCLinkLocal()) {
                    System.out.println(address + " is a subnet wide multicast address.");
                } else if (address.isMCNodeLocal()) {
                    System.out.println(address + " is an interface-local  multicast address.");
                } else {
                    System.out.println(address + " is an unknown  multicast address type.");
                }
            } else {
                System.out.println(address + "is a unicast address.");
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}

URL和URI

URL

相对链接以“/”开头,那么它相对于文档根目录,而不是相对于当前文件。
URL是不可变的(final类)。构造一个URL对象后,其字段不再改变。这有一个副作用:可以保证它们是“线程安全”的。

URL由以下5部分组成:

  1. 模式,也称为协议
  2. 授权机构(用户信息、主机和端口)
  3. 路径
  4. 片段标识符,也称为段或ref(锚点)
  5. 查询字符串
http://www.ibiblio.org/javafaq/books/jnp/index.html?isbn=1565922069#toc

模式:http
授权机构:www.ibiblio.org
路径:/javafaq/books/jnp/index.html
片段标识符:toc
查询字符串:isbn=1565922069

URL equals():当且仅当两个URL都指向相同主机、端口和路径上的相同的资源,而且有相同的片段标识符和查询字符串,才认为这两个URL是相等的。equals()方法会尝试用DNS解析主机,来判断两个主机是否相同。

URI

URI由以下三个部分组成:

  1. 模式
  2. 模式特定部分
  3. 片段标识符

示例代码

URLDemo.java:

import java.io.IOException;
import java.net.URL;

public class URLDemo {
    public static void main(String[] args) throws IOException {
        URL hp = new URL("http://www.HerbSchildt.com/WhatsNew");

        System.out.println("Protocol:" + hp.getProtocol());
        System.out.println("Port:" + hp.getPort());

        System.out.println("Host:" + hp.getHost());
        System.out.println("File:" + hp.getFile());
        System.out.println("Ext:" + hp.toExternalForm());

        System.out.println(hp.openConnection());
    }
}

UCDemo.java:

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;

public class UCDemo {
    public static void main(String[] args) throws IOException {
        int c;
        URL hp = new URL("http://www.internic.net");
        URLConnection hpCon = hp.openConnection();

        long d = hpCon.getDate();
        if (d == 0) {
            System.out.println("No date information.");
        } else {
            System.out.println("Date: " + new Date(d));
        }

        System.out.println("Content-Type:" + hpCon.getContentType());

        d = hpCon.getExpiration();
        if (d == 0) {
            System.out.println("No expiration information.");
        } else {
            System.out.println("Expires:" + new Date(d));
        }

        d = hpCon.getLastModified();
        if (d == 0) {
            System.out.println("No last-modified information.");
        } else {
            System.out.println("Last-Modified:" + new Date(d));
        }

        long len = hpCon.getContentLengthLong();
        if (len == -1) {
            System.out.println("Content length unavailable.");
        } else {
            System.out.println("Content-length:" + len);
        }

        if (len != 0) {
            System.out.println("=== Content ====");
            InputStream input = hpCon.getInputStream();
            while ((c = input.read()) != -1) {
                System.out.print((char) c);
            }
            input.close();
        } else {
            System.out.println("No content available.");
        }

    }
}

HttpURLDemo.java:

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class HttpURLDemo {
    public static void main(String[] args) throws IOException {
        URL hp = new URL("https://www.google.com");
        HttpURLConnection hpCon = (HttpURLConnection) hp.openConnection();

        System.out.println("Request method is " + hpCon.getRequestMethod());

        System.out.println("Response code is " + hpCon.getResponseCode());

        System.out.println("Response Message is " + hpCon.getResponseMessage());

        // 获取标题字段列表和一组标题键。
        Map<String, List<String>> hdrMap = hpCon.getHeaderFields();
        Set<String> hdrField = hdrMap.keySet();

        System.out.println("\nHere is the header:");

        for (String k : hdrField) {
            System.out.println("Key:" + k + " value:" + hdrMap.get(k));
        }
    }
}

Exam1.java:

import java.net.URI;

public class Exam1 {
    public static void main(String[] args) {
        URI uri = URI.create("http://username:[email protected]:80/path/to/file?p1=p1&p2=v2#hash");
        System.out.println(String.format("%s %s %s %s %d %s %s %s",
                uri.getScheme(),
                uri.getAuthority(),
                uri.getUserInfo(),
                uri.getHost(),
                uri.getPort(),
                uri.getPath(),
                uri.getQuery(),
                uri.getFragment()));

        System.out.println("uri.getScheme():" + uri.getScheme());
        // 授权机构,在大多数的情况下,授权机构包括用户信息、主机和端口
        System.out.println("uri.getAuthority():" + uri.getAuthority());
        System.out.println("uri.getUserInfo():" + uri.getUserInfo());
        // URI会自动编解其中的字符串,原生值获取使用下面的
        System.out.println("uri.getRawUserInfo():" + uri.getRawUserInfo());
        System.out.println("uri.getHost():" + uri.getHost());
        System.out.println("uri.getPort():" + uri.getPort());
        System.out.println("uri.getPath():" + uri.getPath());
        System.out.println("uri.getQuery():" + uri.getQuery());
        //fragment 片段标识符
        System.out.println("uri.getFragment():" + uri.getFragment());

    }
}

Exam2.java:

import java.net.MalformedURLException;
import java.net.URL;

public class Exam2 {
    public static void main(String[] args) throws MalformedURLException {
        URL url = new URL("http://www.ibiblio.org/javafaq/books/jnp/index.html?isbn=1565922069#toc");
        System.out.println("getFile():" + url.getFile());
        System.out.println("getHost():" + url.getHost());
        System.out.println("getPort():" + url.getPort());
        System.out.println("getProtocol():" + url.getProtocol());
        System.out.println("getRef():" + url.getRef());
        System.out.println("getQuery():" + url.getQuery());
        System.out.println("getPath():" + url.getPath());
        System.out.println("getUserInfo():" + url.getUserInfo());
        System.out.println("getAuthority():" + url.getAuthority());
    }
}

URLConnection

使用URLConnection类的程序遵循以下基本步骤:

  1. 构造一个URL对象。
  2. 调用这个URL对象的openConnection( )获取一个对应URL的URLConnection对象。
  3. 配置这个URLConnection。
  4. 读取首部字段。
  5. 获得输入流并读取数据。
  6. 获得输出流并写入数据。
  7. 关闭连接。

URL和URLConnection之间的区别:

  • URLConnection提供了对HTTP首部的访问
  • URLConnection可以配置发送给服务器的请求参数
  • URLConnection除了读取服务器数据外,还可以向服务器写入数据。

示例代码

SourceViewer2.java:

import java.io.*;
import java.net.URL;
import java.net.URLConnection;

public class SourceViewer2 {
    public static void main(String[] args) {
        if (args.length > 0) {
            try {
                // 构造URL对象
                URL u = new URL(args[0]);
                // 调用URL对象的openConnection()方法,获取对应的URL的URLConnection对象
                URLConnection uc = u.openConnection();
                // 调用URLConnection的getInputStream()方法
                try (InputStream raw = uc.getInputStream()) {
                    // 使用通常的流API读取输入输入流
                    InputStream buffer = new BufferedInputStream(raw);
                    // 将InputStream串联到一个Reader
                    Reader reader = new InputStreamReader(buffer);
                    int c;
                    while ((c = reader.read()) != -1) {
                        System.out.print((char) c);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

HTTP

从客户端到服务器的每一个请求,都有四个步骤:

  1. 默认情况下,客户端在端口80打开与服务器的一个TCP连接,URL中还可以指定其他端口。
  2. 客户端向服务器发送消息,请求指定路径上的资源。这个请求包括一个首部,可选地还可以有一个空行,后面是这个请求的数据。
  3. 服务器向客户端发送响应。响应以响应码开头,后面是包含元数据的首部、一个空行以及所请求的文档或错误消息。
  4. 服务器关闭连接。
# 请求行;包括一个方法、资源的路径以及HTTP版本。
GET /index.html HTTP/1.1
# 浏览器类型,操作系统版本
User-Agent: Mozilla/5.0 (Macintosh;Intel Mac OS X 10.8; rv:20.0)
Gecko/20100101 Firefox/20.0
# 指定服务器的名
Host: en.wikipedia.org
Connection: keep-alive
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
# 告诉客户端服务器可以处理哪些数据类型
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

HttpURLConnection

HttpURLConnection类是URLConnection的抽象子类,使用方式如下:

URL u = new URL("http://www.baidu.com");
HttpURLConnection http = (HttpURLConnection) u.openConnection();

示例代码

LastModified.java:

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;

public class LastModified {
    public static void main(String[] args) {
        String[] list = {"http://www.ibiblio.org/xml","https://www.baidu.com"};
        for (int i = 0; i < list.length; i++) {
            try {
                URL u = new URL(list[i]);
                HttpURLConnection http = (HttpURLConnection) u.openConnection();
                // 通过setRequestMethod()来改变请求的方法。参数可以是:GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE
                http.setRequestMethod("HEAD");
                System.out.println(u + " was last modified at " + new Date(http.getLastModified()));

            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println();

        }
    }
}

Socket

Socket允许程序员将网络连接看作是另外一个可以读/写字节的流。Socket对程序员掩盖了网络的底层细节,如错误检测、包大小、包分解、包重传、网络地址等。
Socket是两台主机之间的一个连接。它可以完成7个基本操作:

  1. 连接远程机器
  2. 发送数据
  3. 接收数据
  4. 关闭连接
  5. 绑定端口
  6. 监听入站数据
  7. 在绑定端口上接受来自远程机器的连接

半关闭Socket

close()方法同时关闭Socket的输入和输出。shutdownInput()和shutdownOutput()方法可以只关闭连接的一半。
关闭输入之后再读取输入流会返回-1。关闭输出之后再写入Socket则会抛出一个IOException异常。
即使半关闭了连接,或将连接的两半都关闭,使用结束后仍需要关闭该Socket。shutdown方法只影响Socket的流。它们并不释放与Socket关联的资源,如所占用的端口等。
Socket类是Java完成客户端TCP操作的基础类。其他建立TCP网络连接的面向客户端的类(如URL、URLConnection)最终都会调用这个类的方法。这个类本身使用原生代码与主机操作系统的本地TCP栈进行通信。

Socket地址

SocketAddress类的主要用途是为暂时的socket连接信息提供一个方便的存储,即使最初的socket已断开并被垃圾回收,这些信息也可以重用来创建新的Socket。

Socket关闭还是连接

查看一个Socket当前是否打开:

  • isConnected()要返回true(它指出Socket是否从未链接过一个远程主机,链接过返回true,未返回false)
  • isClosed()要返回false。

设置Socket选项

  • TCP_NODELY:设置为true可确保包会尽可能快地发送,而无论包的大小
  • SO_BINDADDR:绑定地址
  • SO_TIMEOUT:设置超时时间,单位为毫秒
  • SO_LINGER:Socket关闭时如何处理尚未发送的数据报
  • SO_SNDBUF:使用缓冲区提升网络性能
  • SO_RCVBUF:使用缓冲区提升网络性能
  • SO_KEEPALIVE:测试包,确保服务器未崩溃
  • OOBINLINE:发送紧急数据
  • IP_TOPS:差分服务

示例代码

DictClient.java:

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

public class DictClient {
    public static final String SERVER = "dict.org";
    public static final int PORT = 2628;
    public static final int TIMEOUT = 15000;

    static void define(String word, Writer writer, BufferedReader reader) throws IOException {
        writer.write("DEFINE eng-lat " + word + "\r\n");
        // 刷新输出,从而确保命令会通过网络发送:
        writer.flush();
        for (String line = reader.readLine(); line != null; line = reader.readLine()) {
            if (line.startsWith("250 ")) {
                return;
            } else if (line.startsWith("552 ")) {
                System.out.println("No definition found for " + word);
                return;
            } else if (line.matches("\\d\\d\\d .*")) {
                continue;
            } else if (line.trim().equals(".")) {
                continue;
            } else {
                System.out.println(line);
            }
        }
    }

    public static void main(String[] args) {
        Socket socket = null;
        try {
            socket = new Socket(SERVER, PORT);
            socket.setSoTimeout(TIMEOUT);
            OutputStream out = socket.getOutputStream();
            Writer writer = new OutputStreamWriter(out, "UTF-8");
            writer = new BufferedWriter(writer);
            InputStream in = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));

            for (String word : args) {
                define(word, writer, reader);
            }
            writer.write("quit\r\n");
            writer.flush();
        } catch (IOException e) {
            System.out.println(e);
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
    }
}

ServerSocket

在Java中,服务器程序的基本生命周期如下:

  1. 使用一个ServerSocket()构造函数在一个特定端口创建一个新的ServerSocket。
  2. ServerSocket使用其accept()方法监听这个端口的入站连接。accept()会一直阻塞,直到一个客户端尝试建立连接,此时accept()将返回一个客户端和服务器的Socket对象。
  3. 根据服务器的类型,会调用Socket的getInputStream()方法或getOutputStream()方法,或者这两个方法都调用,以获得与客户端通信的输入和输出流。
  4. 服务端和客户端根据已协商的协议交互,直到要关闭连接。
  5. 服务器或客户端(或二者)关闭连接。
  6. 服务器回到步骤2,等待下一次连接。

使用InputStream读取客户端,另外使用OutputStream写入客户端。要明确何时写入和何时读取。

关闭ServerSocket会释放本地主机的一个端口,允许另一个服务器绑定到这个端口。

如果需要测试ServerSocket是否打开,就必须同时检查isBound()返回true,而且isClosed()返回false。

关闭ServerSocket会释放本地主机的一个端口,允许另一个服务器绑定到这个端口。它还会中断该ServerSocket已经接受的目前处于打开状态的所有Socket。

示例代码

Daytime.java:

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

public class Daytime {
    public static void main(String[] args) {
        int port = 1024;
        ServerSocket server = null;
        try {
            server = new ServerSocket(port);
            while(true){
                Socket connection = null;
                try {
                    connection = server.accept();
                    Writer out = new OutputStreamWriter(connection.getOutputStream());
                    Date now = new Date();
                    // 需要使用一个回车/换行对来结束这一行。网络服务器中几乎都会这样做
                    out.write(now.toString()+"\r\n");
                    out.flush();
                    // 关闭连接
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                finally {
                    try {
                        if(connection!= null){
                            connection.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (server != null) {
                    server.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

MultithreadDaytimeServer.java:

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

public class MultithreadDaytimeServer {
    public final static int PORT = 1024;

    private static class DaytimeThread extends Thread {
        private Socket connection;

        public DaytimeThread(Socket connection) {
            this.connection = connection;
        }

        @Override
        public void run() {

            try {
                Writer out = new OutputStreamWriter(connection.getOutputStream());
                Date now = new Date();
                out.write(now.toString() + "\r\n");
                out.flush();
            } catch (IOException e) {
                System.err.println(e);
            } finally {
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        try (ServerSocket server = new ServerSocket(PORT)) {

            while (true) {
                Socket connection = server.accept();
                Thread task = new DaytimeThread(connection);
                task.start();
            }

        } catch (IOException e) {
            System.err.println("Couldn't start server");
        }
    }
}

PooledDaytimeServer.java:

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class PooledDaytimeServer {
    public final static int PORT = 1024;

    private static class DaytimeTask implements Callable<Void> {

        private Socket connection;

        public DaytimeTask(Socket connection) {
            this.connection = connection;
        }

        @Override
        public Void call() throws Exception {
            try {
                Writer out = new OutputStreamWriter(connection.getOutputStream());
                Date now = new Date();
                out.write(now.toString() + "\r\n");
                out.flush();
            } catch (IOException e) {
                System.err.println(e);
            } finally {
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }

    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(50);
        try (ServerSocket server = new ServerSocket(PORT)) {
            while (true) {
                try {
                    Socket connection = server.accept();
                    Callable<Void> task = new DaytimeTask(connection);
                    pool.submit(task);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            System.err.println("Cloudn't start server");
        }
    }
}

EchoServer.java:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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.util.Iterator;
import java.util.Set;

public class EchoServer {
    public static int DEFAULT_PORT = 1024;

    public static void main(String[] args) {
        int port;
        
        port = DEFAULT_PORT;
        System.out.println("Listening for connections on port " + port);

        ServerSocketChannel serverChannel;
        Selector selector;

        try {
            // 打开ServerSocketChannel
            serverChannel = ServerSocketChannel.open();
            // 绑定端口
            ServerSocket ss = serverChannel.socket();
            InetSocketAddress address = new InetSocketAddress(port);
            ss.bind(address);
            // 设置为非阻塞
            serverChannel.configureBlocking(false);
            // 打开选择器
            selector = Selector.open();
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }

        while (true) {
            try {
                // 检查是否有可操作的数据
                selector.select();
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
            // 如果选择器确实找到了一个就绪的通道,其selectedKeys()方法会返回一个Set
            Set<SelectionKey> readKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = readKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // 从集合中删除这个键,从而不会处理两次
                iterator.remove();

                try {
                    if (key.isAcceptable()) {
                        // 如果就绪的是服务器通道,程序就会接受一个新的Socket通道,将其添加到选择器
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        SocketChannel client = server.accept();
                        System.out.println("Accepted connection from " + client);
                        client.configureBlocking(false);
                        SelectionKey clientKey = client.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ);
                        ByteBuffer buffer = ByteBuffer.allocate(100);
                        clientKey.attach(buffer);
                    }
                    if (key.isReadable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer output = (ByteBuffer) key.attachment();
                        client.read(output);
                    }
                    if (key.isWritable()) {// 向通道写入数据
                        SocketChannel client = (SocketChannel) key.channel();
                        // 获取键的附件转换为ByteBuffer
                        ByteBuffer output = (ByteBuffer) key.attachment();
                        output.flip();
                        client.write(output);
                        output.compact();
                    }
                } catch (IOException e) {
                    key.channel();
                    try {
                        key.channel().close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        }

    }
}

安全Socket

Java安全Socket扩展(Java Secure Sockets Extension,JSSE)可以使用安全Socket层(Secure Socket Layer,SSL)版本3和传输层安全(Transport Layer Security,TLS)协议及相关的算法来保护网络通信的安全。

SocketFactory factory = SSLSocketFactory.getDefault();
Socket socket = factory.createSocket("login.ibiblio.org",7000);

非阻塞I/O

构造一个新的Selector,只需要调用Selector.open()静态工厂方法:

Selector selector = Selector.open();

使用每个通道的register()方法向监视这个通道的选择器进行注册。

serverChannel.register(selector,SelectionKey.OP_ACCEPT);

猜你喜欢

转载自blog.csdn.net/qq_33704186/article/details/89414990