1. 程式人生 > 實用技巧 >TCP通訊(單執行緒多執行緒)

TCP通訊(單執行緒多執行緒)

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上傳伺服器

  1. ServerSocket套接字物件,監聽埠8888
  2. 方法accept()獲取客戶端的連線物件
  3. 客戶端連線物件獲取位元組輸入流,讀取客戶端傳送圖片
  4. 建立File物件,繫結上傳資料夾

判斷資料夾存在,不存在,再建立資料夾

  1. 建立位元組輸出流,資料目的File物件所在資料夾
  2. 位元組讀取圖片,位元組流將圖片寫入到目的資料夾中
  3. 將上傳成功返回客戶端
  4. 關閉資源

*/

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();//釋放資源
}
}

/*

* 檔案上傳 客戶端

實現步驟:

  1. Socket套接字連線伺服器
  2. 通過Socket獲取位元組輸出流,寫圖片
  3. 使用自己的流物件,讀取圖片資料來源

FileInputStream

  1. 讀取圖片,使用位元組輸出流,將圖片寫到伺服器
  2. 通過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();//釋放資源
}
}