Java入門系列-24-實現網路通訊
阿新 • • 發佈:2018-12-19
網際網路上那麼多裝置,java 是如何與其他裝置通訊的呢?這次的內容是網路通訊的基礎,有了它咱們才能上網頁、玩遊戲、視訊聊天。
Socket 客戶端套接字
Socket 客戶端套接字,用於連線網際網路提供服務的裝置。
Socket 構造方法
構造方法 | 說明 |
---|---|
Socket() | 通過系統預設型別的 SocketImpl 建立未連線套接字 |
Socket(String host, int port) | 建立一個流套接字並將其連線到指定主機上的指定埠號 |
常用方法
方法名稱 | 說明 |
---|---|
getOutputStream() | 返回此套接字的輸出流 |
getInputStream() | 返回此套接字的輸入流 |
下面示例模擬了一個 HTTP 請求
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:實現伺服器套接字,伺服器套接字等待請求通過網路傳入。它基於該請求執行某些操作,然後可能向請求者返回結果。
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 1666
telnet 不是內部或外部命令的讀者,需要在 Windows 功能中啟用 Telnet 客戶端。
上面的程式碼如果有多個客戶端連入就不行了,如果希望服務能被多個客戶端連線,可以使用執行緒。
多執行緒伺服器
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();
}
}
}