P2580 於是他錯誤的點名開始了(字典樹)
實現TCP程式,一個是ServerSocket類,用於表示伺服器端,一個是Socket類,用於表示客戶端。
通訊時,首先建立代表伺服器端的ServerSocket物件,該物件相當於開啟一個服務,並等待客戶端的連線,然後建立代表客戶端的Socket物件向伺服器端發出連線請求,伺服器端響應請求,兩者建立連線開始通訊。
1.1ServerSocket
首先需要建立伺服器端程式
使用該構造方法在建立ServerSocket物件時,就可以將其繫結到一個指定的埠號上(引數port就是埠號)。
//伺服器物件 ServerSocket server=new ServerSocket(9999);//和客戶端建立連線, Socket socket=server.accept();
1.1Socket
ServerSocket物件可以實現服務端程式,但只實現伺服器端程式還不能完成通訊,此時還需要一個客戶端程式與之互動,為此JDK提供了一個Socket類,用於實現TCP客戶端程式
使用該構造方法在建立Socket物件時,會根據引數去連線在指定地址和埠上執行的伺服器程式,其中引數host接收的是一個字串型別的IP地址。
方法宣告 |
功能描述 |
int getPort() |
該方法返回一個int型別物件,該物件是Socket物件與伺服器端連線的埠號 |
InetAddressgetLocalAddress() |
該方法用於獲取Socket物件繫結的本地IP地址,並將IP地址封裝成InetAddress型別的物件返回 |
void close() |
該方法用於關閉Socket連線,結束本次通訊。在關閉socket之前,應將與socket相關的所有的輸入/輸出流全部關閉,這是因為一個良好的程式應該在執行完畢時釋放所有的資源 |
InputStream getInputStream() |
該方法返回一個InputStream型別的輸入流物件,如果該物件是由伺服器端的Socket返回,就用於讀取客戶端傳送的資料,反之,用於讀取伺服器端傳送的資料 |
OutputStream getOutputStream() |
該方法返回一個OutputStream型別的輸出流物件,如果該物件是由伺服器端的Socket返回,就用於向客戶端傳送資料,反之,用於向伺服器端傳送資料 |
實現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 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();//釋放資源 } }