TCP通信
在JDK中提供了兩個類用於實現TCP程序,一個是ServerSocket類,用於表示服務器端,一個是Socket類,用於表示客戶端。
通信時,首先創建代表服務器端的ServerSocket對象,該對象相當於開啟一個服務,並等待客戶端的連接,然后創建代表客戶端的Socket對象向服務器端發出連接請求,服務器端響應請求,兩者建立連接開始通信。
ServerSocket類(服務器端)
方法
ServerSocket對象負責監聽某台計算機的某個端口號,在創建ServerSocket對象后,需要繼續調用該對象的accept()方法,接收來自客戶端的請求。當執行了accept()方法之后,服務器端程序會發生阻塞,直到客戶端發出連接請求,accept()方法才會返回一個Scoket對象用於和客戶端實現通信,程序才能繼續向下執行。
//服務器對象 ServerSocket server=new ServerSocket(9999); //和客戶端創建連接, Socket socket=server.accept();
Socket類(客戶端)
ServerSocket對象可以實現服務端程序,但只實現服務器端程序還不能完成通信,此時還需要一個客戶端程序與之交互,為此JDK提供了一個Socket類,用於實現TCP客戶端程序。
Socket的常用方法
於向服務器端發送數據
在Socket類的常用方法中,getInputStream()和getOutStream()方法分別用於獲取輸入流和輸出流。當客戶端和服務端建立連接后,數據是以IO流的形式進行交互的,從而實現通信。
實現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 { //創建服務器ServerSocket對象(指定服務器端口號) ServerSocket server=new ServerSocket(9999); //和客戶端創建連接, 開啟服務器了,等待客戶端的連接,當客戶端連接后,可以獲取到連接服務器的客戶端Socket對象 Socket socket=server.accept(); //接收客戶端發送數據 InputStream in=socket.getInputStream(); byte[] bytes=new byte[1024]; //獲取客戶端發送的數據 int len=in.read(bytes); //獲取ip String ip=socket.getInetAddress().getHostAddress(); System.out.println("ip地址為:"+ip+"客戶端發送的數據為"+new String(bytes,0,len)); //回復客戶端 //獲取字節輸出流 OutputStream out=socket.getOutputStream(); //向客戶端發送數據 out.write("收到".getBytes()); //釋放資源 server.close(); } }
實現客戶端服務器程序
實現TCP 客戶端,連接到服務器
* 和服務器實現數據交換
* 實現TCP客戶端程序的類 java.net.Soket
* 構造方法
* Socket(String host,int port) 傳遞服務器IP和端口號
* 注意:構造方法只要運行,就會和服務器進行連接,連接失敗,拋出異常
* OutputStream getOutputStream() 返回套接字的輸出流
* 作用:將數據輸出,輸出到服務器
* InputStream getInputStream() 返回套接字的輸入流
* 作用:從服務器端讀取數據
* 客戶端服務器數據交換,必須使用套接字對象Socket中的獲取的IO流,自己new流,不行
* 1,創建客戶端Socket對象,(指定要連接的服務器地址與端口號)
* 2,獲取服務器端的反饋回來的信息
* 3,關閉流資源
//客戶端TCP public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { //創建客戶端Socket對象,(指定要連接的服務器地址與端口號) Socket socket=new Socket("127.0.0.1",9999); //獲取字節輸出流,向客戶端發送數據 OutputStream out=socket.getOutputStream(); out.write("你好".getBytes()); //接收服務器端的回復 //獲取字節輸入流 InputStream in=socket.getInputStream(); byte[] bytes=new byte[1024]; //把流中的數據存儲到數組中,並記錄讀取字節的個數 int len=in.read(bytes); //獲取ip地址 String ip=socket.getInetAddress().getHostAddress(); System.out.println("ip為"+ip+"內容"+new String(bytes,0,len)); socket.close();//釋放資源 } }
文件上傳
/*
* TCP上傳服務器
- ServerSocket套接字對象,監聽端口8888
- 方法accept()獲取客戶端的連接對象
- 客戶端連接對象獲取字節輸入流,讀取客戶端發送圖片
- 創建File對象,綁定上傳文件夾
判斷文件夾存在,不存在,再創建文件夾
- 創建字節輸出流,數據目的File對象所在文件夾
- 字節讀取圖片,字節流將圖片寫入到目的文件夾中
- 將上傳成功返回客戶端
- 關閉資源
*/
public class TCPServer { public static void main(String[] args) throws IOException { //創建服務器對象,明確端口號 ServerSocket server=new ServerSocket(9999); //創建於客戶端的連接 Socket socket=server.accept(); //明確數據源,顯示哪個客戶端Socket連接上了服務器 InputStream in=socket.getInputStream(); File file=new File("D:\\io0512\\server"); if(!file.exists()){ file.mkdirs(); } String filename="oracle"+System.currentTimeMillis()+new Random().nextInt(99999)+".java"; //明確目的地 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();//釋放資源 } }
/*
* 文件上傳 客戶端
實現步驟:
- Socket套接字連接服務器
- 通過Socket獲取字節輸出流,寫圖片
- 使用自己的流對象,讀取圖片數據源
FileInputStream
- 讀取圖片,使用字節輸出流,將圖片寫到服務器
- 通過Socket套接字獲取字節輸入流
讀取服務器發回來的上傳成功
6.關閉資源
*
* public void shutdownOutput() 禁用此Socket的輸出流,間接的相當於告知了服務器數據寫入完畢
*/
//客戶端TCP public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { //創建客戶端Socket對象,(指定要連接的服務器地址與端口號) Socket socket=new Socket("127.0.0.1",9999); //獲取字節輸出流,向客戶端發送數據 OutputStream out=socket.getOutputStream(); out.write("你好".getBytes()); //接收服務器端的回復 //獲取字節輸入流 InputStream in=socket.getInputStream(); byte[] bytes=new byte[1024]; //把流中的數據存儲到數組中,並記錄讀取字節的個數 int len=in.read(bytes); //獲取ip地址 String ip=socket.getInetAddress().getHostAddress(); System.out.println("ip為"+ip+"內容"+new String(bytes,0,len)); socket.close();//釋放資源 } }
多線程版本
實現服務器端可以同時接收多個客戶端上傳的文件。
服務器端
public class Upload implements Runnable{ private Socket socket; public Upload(Socket socket){ this.socket=socket; } public void run() { //明確數據源,顯示哪個客戶端Socket連接上了服務器 InputStream in; try { in = socket.getInputStream(); File file=new File("D:\\io0512\\server"); if(!file.exists()){ file.mkdirs(); } String filename="oracle"+System.currentTimeMillis()+new Random().nextInt(99999)+".jpg"; //明確目的地 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()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
public class Demo01 { public static void main(String[] args) throws IOException { //創建服務器對象 ServerSocket server=new ServerSocket(9999); while(true){ Socket socket=server.accept(); //啟動線程,完成與當前客戶端的數據交互過程 new Thread(new Upload(socket)).start();//創建線程任務 } } }
客戶端
//客戶端 public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { //創建客戶端對象,明確地址和端口號 Socket socket=new Socket("192.168.1.151",9999); //明確數據源 FileInputStream fis=new FileInputStream("D:\\背景\\1.jpg"); //明確目的地 OutputStream out=socket.getOutputStream();//服務器端 //開始復制 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();//釋放資源 } }