網路安全協議(二)
一、TCP通訊
TCP通訊同UDP通訊一樣,都能實現兩臺計算機之間的通訊,通訊的兩端都需要建立socket物件。
區別在於,UDP中只有傳送端和接收端,不區分客戶端與伺服器端,計算機之間可以任意地傳送資料。
而TCP通訊是嚴格區分客戶端與伺服器端的,在通訊時,必須先由客戶端去連線伺服器端才能實現通訊,伺服器端不可以主動連線客戶端,並且伺服器端程式需要事先啟動,等待客戶端的連線。
在JDK中提供了兩個類用於實現TCP程式,一個是ServerSocket類,用於表示伺服器端,一個是Socket類,用於表示客戶端。
通訊時,首先建立代表伺服器端的ServerSocket物件,該物件相當於開啟一個服務,並等待客戶端的連線,然後建立代表客戶端的Socket物件向伺服器端發出連線請求,伺服器端響應請求,兩者建立連線開始通訊。
1、ServerSocket
構造方法:
使用該構造方法在建立ServerSocket物件時,就可以將其繫結到一個指定的埠號上(引數port就是埠號)。
常用方法:
2、Socket
常用構造方法:
使用該構造方法在建立Socket物件時,會根據引數去連線在指定地址和埠上執行的伺服器程式,其中引數host接收的是一個字串型別的IP地址。
該方法在使用上與第二個構造方法類似,引數address用於接收一個InetAddress型別的物件,該物件用於封裝一個IP地址。
常用方法:
方法宣告 |
功能描述 |
int getPort() |
該方法返回一個int型別物件,該物件是Socket物件與伺服器端連線的埠號 |
InetAddressgetLocalAddress() |
該方法用於獲取Socket物件繫結的本地IP地址,並將IP地址封裝成InetAddress型別的物件返回 |
void close() |
該方法用於關閉Socket連線,結束本次通訊。在關閉socket之前,應將與socket相關的所有的輸入/輸出流全部關閉,這是因為一個良好的程式應該在執行完畢時釋放所有的資源 |
InputStream getInputStream() |
該方法返回一個InputStream型別的輸入流物件,如果該物件是由 |
OutputStream getOutputStream() |
該方法返回一個OutputStream型別的輸出流物件,如果該物件是由伺服器端的Socket返回,就用於向客戶端傳送資料,反之,用於向伺服器端傳送資料 |
二、簡單的TCP網路程式
要實現TCP通訊需要建立一個伺服器端程式和一個客戶端程式,為了保證資料傳輸的安全性,首先需要實現伺服器端程式。
/* * 實現TCP 伺服器程式 * 表示伺服器程式的類 java.net.ServerSocket * 構造方法: * ServerSocket(int port)傳遞埠號 * 很重要的事情:必須要獲得客戶端的套接字物件Socket * Socket accept() * * 1,建立伺服器ServerSocket物件(指定伺服器埠號) * 2,開啟伺服器了,等待客戶端的連線,當客戶端連線後,可以獲取到連線伺服器的客戶端Socket物件 * 3,給客戶端反饋資訊 * 4,關閉流資源 */ public class TCPServer { public static void main(String[] args) throws IOException { //1,建立伺服器ServerSocket物件(指定伺服器埠號) ServerSocket ss = new ServerSocket(8888); //2,開啟伺服器了,等待客戶端的連線,當客戶端連線後,可以獲取到連線伺服器的客戶端Socket物件 Socket s = ss.accept(); //3,給客戶端反饋資訊 /* * a,獲取客戶端的輸出流 * b,在服務端端,通過客戶端的輸出流寫資料給客戶端 */ //a,獲取客戶端的輸出流 OutputStream out = s.getOutputStream(); //b,在服務端端,通過客戶端的輸出流寫資料給客戶端 out.write("你已經連線上了伺服器".getBytes()); //4,關閉流資源 out.close(); s.close(); //ss.close(); 伺服器流 通常都是不關閉的 } }
完成了伺服器端程式的編寫,接下來編寫客戶端程式。
/* * 實現TCP 客戶端,連線到伺服器 * 和伺服器實現資料交換 * 實現TCP客戶端程式的類 java.net.Soket * 構造方法 * Socket(String host,int port) 傳遞伺服器IP和埠號 * 注意:構造方法只要執行,就會和伺服器進行連線,連線失敗,丟擲異常 * OutputStream getOutputStream() 返回套接字的輸出流 * 作用:將資料輸出,輸出到伺服器 * InputStream getInputStream() 返回套接字的輸入流 * 作用:從伺服器端讀取資料 * 客戶端伺服器資料交換,必須使用套接字物件Socket中的獲取的IO流,自己new流,不行 * 1,建立客戶端Socket物件,(指定要連線的伺服器地址與埠號) * 2,獲取伺服器端的反饋回來的資訊 * 3,關閉流資源 */ public class TCPClient { public static void main(String[] args) throws IOException { //1,建立客戶端Socket物件,(指定要連線的伺服器地址與埠號) Socket s = new Socket("192.168.74.58", 8888); //2,獲取伺服器端的反饋回來的資訊 InputStream in = s.getInputStream(); //獲取獲取流中的資料 byte[] buffer = new byte[1024]; //把流中的資料儲存到陣列中,並記錄讀取位元組的個數 int length = in.read(buffer); //顯示資料 System.out.println( new String(buffer, 0 , length) ); //3,關閉流資源 in.close(); s.close(); } }
三、檔案上傳案例
首先編寫伺服器端程式,用來接收圖片。
/* * TCP上傳伺服器 1.ServerSocket套接字物件,監聽埠8888 2.方法accept()獲取客戶端的連線物件 3.客戶端連線物件獲取位元組輸入流,讀取客戶端傳送圖片 4.建立File物件,繫結上傳資料夾 判斷資料夾存在,不存在,再建立資料夾 5.建立位元組輸出流,資料目的File物件所在資料夾 6.位元組讀取圖片,位元組流將圖片寫入到目的資料夾中 7.將上傳成功返回客戶端 8.關閉資源 */ public class TCPServer { public static void main(String[] args) throws IOException { //1,建立伺服器,等待客戶端連線 ServerSocket serverSocket = new ServerSocket(8888); Socket clientSocket = serverSocket.accept(); //顯示哪個客戶端Socket連線上了伺服器 InetAddress ipObject = clientSocket.getInetAddress();//得到IP地址物件 String ip = ipObject.getHostAddress(); //得到IP地址字串 System.out.println("小樣,抓到你了,連線我!!" + "IP:" + ip); //7,獲取Socket的輸入流 InputStream in = clientSocket.getInputStream(); //8,建立目的地的位元組輸出流 D:\\upload\\192.168.74.58(1).jpg BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream("D:\\upload\\192.168.74.58(1).jpg")); //9,把Socket輸入流中的資料,寫入目的地的位元組輸出流中 byte[] buffer = new byte[1024]; int len = -1; while((len = in.read(buffer)) != -1){ //寫入目的地的位元組輸出流中 fileOut.write(buffer, 0, len); } //-----------------反饋資訊--------------------- //10,獲取Socket的輸出流, 作用:寫反饋資訊給客戶端 OutputStream out = clientSocket.getOutputStream(); //11,寫反饋資訊給客戶端 out.write("圖片上傳成功".getBytes()); out.close(); fileOut.close(); in.close(); clientSocket.close(); //serverSocket.close(); } }
編寫客戶端,完成上傳圖片
/* * 檔案上傳 客戶端 實現步驟: 1.Socket套接字連線伺服器 2.通過Socket獲取位元組輸出流,寫圖片 3.使用自己的流物件,讀取圖片資料來源 FileInputStream 4.讀取圖片,使用位元組輸出流,將圖片寫到伺服器 5.通過Socket套接字獲取位元組輸入流 讀取伺服器發回來的上傳成功 6.關閉資源 * * public void shutdownOutput() 禁用此Socket的輸出流,間接的相當於告知了伺服器資料寫入完畢 */ public class TCPClient { public static void main(String[] args) throws IOException { //2,建立客戶端Socket,連線伺服器 Socket socket = new Socket("192.168.74.58", 8888); //3,獲取Socket流中的輸出流,功能:用來把資料寫到伺服器 OutputStream out = socket.getOutputStream(); //4,建立位元組輸入流,功能:用來讀取資料來源(圖片)的位元組 BufferedInputStream fileIn = new BufferedInputStream(new FileInputStream("D:\\NoDir\\test.jpg")); //5,把圖片資料寫到Socket的輸出流中(把資料傳給伺服器) byte[] buffer = new byte[1024]; int len = -1; while ((len = fileIn.read(buffer)) != -1){ //把資料寫到Socket的輸出流中 out.write(buffer, 0, len); } //6,客戶端傳送資料完畢,結束Socket輸出流的寫入操作,告知伺服器端 socket.shutdownOutput(); //-----------------反饋資訊--------------------- //12,獲取Socket的輸入流 作用: 讀反饋資訊 InputStream in = socket.getInputStream(); //13,讀反饋資訊 byte[] info = new byte[1024]; //把反饋資訊儲存到info陣列中,並記錄位元組個數 int length = in.read(info); //顯示反饋結果 System.out.println( new String(info, 0, length) ); //關閉流 in.close(); fileIn.close(); out.close(); socket.close(); } }