Java – 網絡編程

使用 Java 進行網絡編程時,由虛擬機實現了底層複雜的網絡協議,Java 程序只需要調用 Java 標準庫提供的接口,就可以簡單高效地編寫網絡程序。Java 提供的這些標準庫存在於 java.net 包下。

TCP 編程

Socket 是一個抽象概念,一個應用程序通過一個 Socket 來建立一個遠程連接,而 Socket 內部通過 TCP/IP 協議把數據傳輸到網絡。Socket、TCP 和部分 IP 的功能都是由操作系統提供的,不同的編程語言只是提供了對操作系統調用的簡單的封裝。

服務端

public class Server {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        OutputStream output = null;
        try {
            serverSocket = new ServerSocket(8888);
            System.out.println("Server is running...");
            // 沒連接就會阻塞
            socket = serverSocket.accept();
            output = socket.getOutputStream();
            output.write("您好,歡迎訪問服務端!".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally { //由下向上,依次關閉
            if(output != null ){
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket != null ){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(serverSocket != null ){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

結果:Server is running...

客戶端

public class Client {
    public static void main(String[] args) {
        Socket socket = null;
        InputStream input = null;
        try {
            InetAddress addressIP = InetAddress.getByName("127.0.0.1");
            int port = 8888;
            socket = new Socket(addressIP, port); //嘗試建立連接
            input = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int len;
            StringBuilder sb = new StringBuilder();
            while ((len = input.read(bytes)) != -1) {
                sb.append(new String(bytes, 0, len, "UTF-8"));
            }
            System.out.println(sb);

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

結果:您好,歡迎訪問服務端!

UDP 編程

UDP編程就簡單得多,因爲UDP沒有創建連接,數據包也是一次收發一個,所以沒有流的概念。

服務端

public class Server {
    public static void main(String[] args) {
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket(6666); // 監聽指定端口
            for (;;) {
                // 數據緩衝區:
                byte[] buffer = new byte[1024];
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                ds.receive(packet); // 收取一個UDP數據包
                String s = new String(packet.getData(), packet.getOffset(), packet.getLength(), StandardCharsets.UTF_8);
                System.out.println(s);
                // 發送數據:
                byte[] data = "請求已收到!".getBytes(StandardCharsets.UTF_8);
                packet.setData(data);
                ds.send(packet);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            ds.close();
        }
    }
}

結果:你好,我發了個包!

客戶端

public class Client {
    public static void main(String[] args) {
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket();
            ds.setSoTimeout(1000);
            ds.connect(InetAddress.getByName("localhost"), 6666);
            // 發送:
            byte[] data = "你好,我發了個包!".getBytes();
            DatagramPacket packet = new DatagramPacket(data, data.length);
            ds.send(packet);
            // 接收:
            byte[] buffer = new byte[1024];
            packet = new DatagramPacket(buffer, buffer.length);
            ds.receive(packet);
            String resp = new String(packet.getData(), packet.getOffset(), packet.getLength());
            System.out.println(resp);
            ds.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            ds.close();
        }
    }
}

結果:請求已收到!

HTTP 編程

HTTP 是 HyperText Transfer Protocol 的縮寫,翻譯爲超文本傳輸協議,它是基於 TCP 協議之上的一種請求-響應協議。HTTP 請求的格式是固定的,它由 HTTP Header 和 HTTP Body 兩部分構成。

服務端

服務器端的 HTTP 編程本質上就是編寫 Web 服務器,這是一個非常複雜的體系,也是 JavaEE 開發的核心內容,本次就不實現了。

客戶端

瀏覽器也是一種 HTTP 客戶端,客戶端的 HTTP 編程,它的行爲本質上和瀏覽器是一樣的,即發送一個 HTTP 請求,接收服務器響應後,獲得響應內容。

public class Client {
    public static void main(String[] args) throws IOException {
        URL url = new URL("https://www.baidu.com/");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setUseCaches(false);
        conn.setConnectTimeout(5000); // 請求超時5秒
        // 設置HTTP頭:
        conn.setRequestProperty("Accept", "*/*");
        conn.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 11; Windows NT 5.1)");
        // 連接併發送HTTP請求:
        conn.connect();
        // 判斷HTTP響應是否200:
        if (conn.getResponseCode() != 200) {
            throw new RuntimeException("bad response");
        }
        // 獲取所有響應Header:
        Map<String, List<String>> map = conn.getHeaderFields();
        for (String key : map.keySet()) {
            System.out.println(key + ": " + map.get(key));
        }
        // 獲取響應內容:
        InputStream input = conn.getInputStream();
    }
}

從 Java 11 開始,引入了新的 HttpClient,它使用鏈式調用的 API,能大大簡化 HTTP 的處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章