Java入門系列-24-實現網絡通訊

互聯網上那麼多設備,java 是如何與其餘設備通訊的呢?此次的內容是網絡通訊的基礎,有了它我們才能上網頁、玩遊戲、視頻聊天。java

Socket 客戶端套接字

Socket 客戶端套接字,用於鏈接互聯網提供服務的設備。服務器

Socket 構造方法網絡

構造方法 說明
Socket() 經過系統默認類型的 SocketImpl 建立未鏈接套接字
Socket(String host, int port) 建立一個流套接字並將其鏈接到指定主機上的指定端口號

經常使用方法多線程

方法名稱 說明
getOutputStream() 返回此套接字的輸出流
getInputStream() 返回此套接字的輸入流

下面示例模擬了一個 HTTP 請求app

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class TestSocket {

    public static void main(String[] args) {
        
        //建立套接字
        try(Socket s=new Socket("www.baidu.com", 80);){
            //建立向服務器發送數據的輸出流
            OutputStream os=s.getOutputStream();
            StringBuffer sb=new StringBuffer();
            //HTTP協議 請求報文
            sb.append("GET / HTTP/1.1\r\n");
            sb.append("Host: www.baidu.com:80\r\n");
            sb.append("Connection: Keep-Alive\r\n");
            //這裏必定要一個回車換行,表示消息頭完,否則服務器會等待
            sb.append("\r\n");
            //發送
            os.write(sb.toString().getBytes());
            //獲取服務器相應內容 
            InputStream is=s.getInputStream();
            //經過輸入流建立掃描器,並指定編碼爲utf-8防止中文亂碼
            Scanner scanner=new Scanner(is,"utf-8");
            
            while(scanner.hasNextLine()) {
                String line=scanner.nextLine();
                System.out.println(line);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
            System.out.println("未知主機");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO異常");
        }
    }
}

ServerSocket

ServerSocket:實現服務器套接字,服務器套接字等待請求經過網絡傳入。它基於該請求執行某些操做,而後可能向請求者返回結果。socket

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TestServerSocket {

    public static void main(String[] args) {
        //建立 ServerSocket 監聽1666端口
        try(ServerSocket server=new ServerSocket(1666)){
            //阻塞方法,當有客戶端連入,獲取客戶端Socket
            try(Socket client=server.accept()){
                //獲取客戶端發送的數據
                InputStream is=client.getInputStream();
                //獲取向客戶端發送數據的流
                OutputStream os=client.getOutputStream();
                //經過輸入流建立掃描器
                try(Scanner scanner=new Scanner(is)){
                    
                    PrintWriter pw=new PrintWriter(os,true/*自動刷新*/);
                    //向客戶端發送消息
                    pw.println("Hello,enter bye to exit.");
                    boolean done=false;
                    //客戶端有輸入數據而且沒有發送 bye 
                    while(!done&&scanner.hasNextLine()) {
                        //接收客戶端發送的數據
                        String line=scanner.nextLine();
                        //將客戶端發送的數據發回客戶端
                        pw.println("Echo:"+line);
                        //若是客戶端輸入bye 結束通訊
                        if(line.trim().equalsIgnoreCase("bye")) {done=true;}
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

測試方式:
在DOS 中輸入命令:telnet 127.0.0.1 1666ide

telnet 不是內部或外部命令的讀者,須要在 Windows 功能中啓用 Telnet 客戶端。測試

上面的代碼若是有多個客戶端連入就不行了,若是但願服務能被多個客戶端鏈接,可使用線程。this

多線程服務器編碼

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TestMultiServerSocket {

    public static void main(String[] args) {
        //建立 ServerSocket 監聽 1666端口
        try(ServerSocket server=new ServerSocket(1666)){
            while(true) {
                //accept() 是一個阻塞方法
                Socket client=server.accept();
                InputStream is=client.getInputStream();
                OutputStream os=client.getOutputStream();
                //開啓新的線程處理,傳入當前客戶端
                Thread t=new Thread(new ThreadEchoHandler(client));
                t.start();              
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
class ThreadEchoHandler implements Runnable{
    private Socket socket=null;

    public ThreadEchoHandler(Socket socket) {
        this.socket=socket;
    }
    @Override
    public void run() {
        try {
            InputStream is=socket.getInputStream();
            OutputStream os=socket.getOutputStream();
            try(Scanner scanner=new Scanner(is)){
                PrintWriter pw=new PrintWriter(os,true);
                pw.println("Hello,enter bye to exit.");
                boolean done=false;
                while(!done&&scanner.hasNextLine()) {
                    String line=scanner.nextLine();
                    pw.println("Echo:"+line);
                    if(line.trim().equalsIgnoreCase("bye")) {done=true;}
                }
            }
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

URLConnection

抽象類 URLConnection 是全部類的超類,它表明應用程序和 URL 之間的通訊連接。此類的實例可用於讀取和寫入此 URL 引用的資源。

Socket 能夠默認任意類型的網絡通訊,URLConnection 更適合 HTTP 請求,使用 URLConnection 進行HTTP操做更方便,模擬請求報文,獲取響應報文和內容。

URLConnection 經常使用方法

方法 說明
connect() 打開到此 URL 引用的資源的通訊連接(若是還沒有創建這樣的鏈接)
getContentEncoding() 返回 content-encoding 頭字段的值
getContentType() 返回 content-type 頭字段的值
getHeaderFields() 返回頭字段的不可修改的 Map
getInputStream() 返回今後打開的鏈接讀取的輸入流
setRequestProperty(String key, String value) 設置通常請求屬性

獲取 URLConnection 須要先建立 URL 對象:
URL url=new URL(host);

使用 URLConnection 獲取網頁的內容

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;

public class TestURLConnection {
    public static void main(String[] args) {
        
        try {
            //建立URL對象
            URL url=new URL("http://www.baidu.com");
            //建立 URLConnection對象
            URLConnection connection=url.openConnection();
            //設置請求屬性
            //connection.setRequestProperty("", "");
            //鏈接
            connection.connect();
            //獲取輸入流
            InputStream is=connection.getInputStream();
            //經過輸入流構建一個掃描器
            Scanner scanner=new Scanner(is,"utf-8");
            while(scanner.hasNextLine()) {
                String line=scanner.nextLine();
                System.out.println(line);
            }
            System.out.println("===響應頭===");
            Map<String,List<String>> headers=connection.getHeaderFields();
            for (Entry<String, List<String>> entry: headers.entrySet()) {
                String key=entry.getKey();
                System.out.print(key+":");
                for (String string : entry.getValue()) {
                    System.out.print(string);
                }
                System.out.println();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
相關文章
相關標籤/搜索