1 TCP協議
TCP協議是面向連接的通信協議,即在傳輸數據前先在發送端和接收端建立邏輯連接,然后再傳輸數據,它提供了兩台計算機之間可靠無差錯的數據傳輸。
在TCP連接中必須要明確客戶端與服務器端,由客戶端向服務端發出連接請求,每次連接的創建都需要經過“三次握手”。
第一次握手,客戶端向服務器端發出連接請求,等待服務器確認
第二次握手,服務器端向客戶端回送一個響應,通知客戶端收到了連接請求
第三次握手,客戶端再次向服務器端發送確認信息,確認連接
下載文件時必須采用TCP協議。
2 TCP通信
TCP通信同UDP通信一樣,都能實現兩台計算機之間的通信,通信的兩端都需要創建socket對象。
在JDK中提供了兩個類用於實現TCP程序,一個是ServerSocket類,用於表示服務器端,一個是Socket類,用於表示客戶端。
2.1 ServerSocket
ServerSocket的構造方法:
ServerSocket的常用方法:
ServerSocket對象負責監聽某台計算機的某個端口號,在創建ServerSocket對象后,需要繼續調用該對象的accept()方法,接收來自客戶端的請求。當執行了accept()方法之后,服務器端程序會發生阻塞,直到客戶端發出連接請求,accept()方法才會返回一個Scoket對象用於和客戶端實現通信,程序才能繼續向下執行。
2.2 Socket
在Socket類的常用方法中,getInputStream()和getOutStream()方法分別用於獲取輸入流和輸出流。當客戶端和服務端建立連接后,數據是以IO流的形式進行交互的,從而實現通信。
2.3 簡單的TCP網絡程序
要實現TCP通信需要創建一個服務器端程序和一個客戶端程序,為了保證數據傳輸的安全性,首先需要實現服務器端程序。
服務器端:
//TCP服務器端 public class TCPServer { public static void main(String[] args) throws IOException { //1.創建服務器套接字對象 ServerSocket server=new ServerSocket(8888); //2.調用accept方法,創建連接,獲取客戶端的套接字對象Socket Socket socket=server.accept(); //3.從客戶端套接字對象中獲取字節輸入流 InputStream in=socket.getInputStream(); byte[] bytes=new byte[1024]; int len=in.read(bytes); System.out.println(new String(bytes,0,len)); String ip=socket.getInetAddress().getHostAddress(); System.out.println("來自此ip地址:"+ip); //發送給客戶端一個響應(回復) //獲取字節輸出流 OutputStream out=socket.getOutputStream(); Scanner sc=new Scanner(System.in); String str=sc.next(); out.write(str.getBytes()); //4.釋放資源 server.close(); } }
客戶端:
//TCP客戶端 public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { //1.創建Socket對象,連接服務器 Socket socket=new Socket("192.168.1.147",8888); //2.通過客戶端Socket對象中的方法,獲取字節輸出流,將數據寫向服務器 OutputStream out=socket.getOutputStream(); //3.寫數據 Scanner sc=new Scanner(System.in); String str=sc.next(); out.write(str.getBytes()); //接收服務器端的響應 //獲取字節輸入流 InputStream in=socket.getInputStream(); byte[] bytes=new byte[1024]; int len=in.read(bytes); System.out.println(new String(bytes,0,len)); //4.釋放資源 socket.close(); } }
2.4 文件的上傳案例
服務器端:
//服務器端 public class TCPServer { public static void main(String[] args) throws IOException { //1.創建服務器套接字,綁定端口號 ServerSocket server=new ServerSocket(8888); //2.調用accept方法,與客戶端創建連接,獲取客戶端套接字對象 Socket socket=server.accept(); //3.獲取字節輸入流,明確數據源 InputStream in=socket.getInputStream(); //4.明確目的地 File file=new File("D:\\upload"); //判定該文件夾是否存在,不存在則創建 if(!file.exists()){ file.mkdirs(); } //域名+毫秒值+六位隨機數 String filename="oracle"+System.currentTimeMillis()+new Random().nextInt(999999)+".png"; FileOutputStream fos=new FileOutputStream(file+File.separator+filename); //開始復制 byte[] bytes=new byte[1024]; int len=0; while((len=in.read(bytes))!=-1){ fos.write(bytes,0,len); } //給客戶端響應(回復) //獲取字節輸出流 OutputStream out=socket.getOutputStream(); out.write("上傳成功".getBytes()); //釋放資源 server.close(); fos.close(); } }
客戶端:
//客戶端 public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { //1.創建客戶端套接字Socket對象,連接服務器 Socket socket=new Socket("192.168.1.147",8888); //2.通過Socket獲取字節輸出流 OutputStream out=socket.getOutputStream(); //明確數據源 FileInputStream fis=new FileInputStream("E:\\java\\pp.png"); //開始復制 int len=0; byte[] bytes=new byte[1024]; while((len=fis.read(bytes))!=-1){ out.write(bytes,0,len); } //告訴服務器端當前字節已經讀完,不用等了 socket.shutdownOutput(); //接收服務器端的回復 //獲取字節輸入流 InputStream in=socket.getInputStream(); len=in.read(bytes); System.out.println(new String(bytes,0,len)); //釋放資源 socket.close(); fis.close(); } }