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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章