java TCP 通信:服務端與客服端


1、首先先來看下基於TCP協議Socket服務端和客戶端的通信模型:

 

Socket通信步驟:(簡單分為4步)

1.建立服務端ServerSocket和客戶端Socket

2.打開連接到Socket的輸出輸入流

3.按照協議進行讀寫操作

4.關閉相對應的資源

 

2、相關聯的API:

 

1.首先先來看下ServerSocket

類 ServerSocket 

此類實現服務器套接字。服務器套接字等待請求通過網絡傳入。它基於該請求執行某些操作,然后可能向請求者返回結果。

服務器套接字的實際工作由 SocketImpl 類的實例執行。應用程序可以更改創建套接字實現的套接字工廠來配置它自身,從而創建適合本地防火牆的套接字。 

一些重要的方法:(具體大家查看官方api吧)

ServerSocket(int port, int backlog) 
利用指定的 backlog 創建服務器套接字並將其綁定到指定的本地端口號。

bind(SocketAddress endpoint, int backlog) 
將 ServerSocket 綁定到特定地址(IP 地址和端口號)。

accept() 
偵聽並接受到此套接字的連接

getInetAddress() 
返回此服務器套接字的本地地址。

 close() 
關閉此套接字。

 

2.再來看下Socket

類 Socket  

此類實現客戶端套接字(也可以就叫“套接字”)。套接字是兩台機器間通信的端點。

套接字的實際工作由 SocketImpl 類的實例執行。應用程序通過更改創建套接字實現的套接字工廠可以配置它自身,以創建適合本地防火牆的套接字。

一些重要的方法:(具體大家查看官方api吧)

Socket(InetAddress address, int port) 
創建一個流套接字並將其連接到指定 IP 地址的指定端口號。

getInetAddress() 
返回套接字連接的地址。

shutdownInput() 
此套接字的輸入流置於“流的末尾”。

shutdownOutput() 
禁用此套接字的輸出流。

close() 
關閉此套接字。

 

3、代碼實現:(注釋很全,這里就不詳細多說了)

服務端Server.java

1.創建ServerSocket對象,綁定並監聽端口

2.通過accept監聽客戶端的請求

3.建立連接后,通過輸出輸入流進行讀寫操作

4.關閉相關資源

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;


public class Server {

    /**
     * Socket服務端
     */
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket=new ServerSocket(8888);
            System.out.println("服務端已啟動,等待客戶端連接..");
            Socket socket=serverSocket.accept();//偵聽並接受到此套接字的連接,返回一個Socket對象
            
            
            //根據輸入輸出流和客戶端連接
            InputStream inputStream=socket.getInputStream();//得到一個輸入流,接收客戶端傳遞的信息
            InputStreamReader inputStreamReader=new InputStreamReader(inputStream);//提高效率,將自己字節流轉為字符流
            BufferedReader bufferedReader=new BufferedReader(inputStreamReader);//加入緩沖區
            String temp=null;
            String info="";
            while((temp=bufferedReader.readLine())!=null){
                info+=temp;
                System.out.println("已接收到客戶端連接");
                System.out.println("服務端接收到客戶端信息:"+info+",當前客戶端ip為:"+socket.getInetAddress().getHostAddress());
            }
            
            OutputStream outputStream=socket.getOutputStream();//獲取一個輸出流,向服務端發送信息
            PrintWriter printWriter=new PrintWriter(outputStream);//將輸出流包裝成打印流
            printWriter.print("你好,服務端已接收到您的信息");
            printWriter.flush();
            socket.shutdownOutput();//關閉輸出流
            
            
            
            //關閉相對應的資源
            printWriter.close();
            outputStream.close();
            bufferedReader.close();
            inputStream.close();
            socket.close();
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

客戶端Client.java

1.創建Socket對象,指定服務端的地址和端口號

2.建立連接后,通過輸出輸入流進行讀寫操作

3.通過輸出輸入流獲取服務器返回信息

4.關閉相關資源

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;


public class Client {

    /**
     * Socket客戶端
     */
    public static void main(String[] args) {
        try {
            //創建Socket對象
            Socket socket=new Socket("localhost",8888);
            
            //根據輸入輸出流和服務端連接
            OutputStream outputStream=socket.getOutputStream();//獲取一個輸出流,向服務端發送信息
            PrintWriter printWriter=new PrintWriter(outputStream);//將輸出流包裝成打印流
            printWriter.print("服務端你好,我是Balla_兔子");
            printWriter.flush();
            socket.shutdownOutput();//關閉輸出流
            
            InputStream inputStream=socket.getInputStream();//獲取一個輸入流,接收服務端的信息
            InputStreamReader inputStreamReader=new InputStreamReader(inputStream);//包裝成字符流,提高效率
            BufferedReader bufferedReader=new BufferedReader(inputStreamReader);//緩沖區
            String info="";
            String temp=null;//臨時變量
            while((temp=bufferedReader.readLine())!=null){
                info+=temp;
                System.out.println("客戶端接收服務端發送信息:"+info);
            }
            
            //關閉相對應的資源
            bufferedReader.close();
            inputStream.close();
            printWriter.close();
            outputStream.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

4、效果截圖:

服務端:

客戶端:

以上代碼實現了單客戶端和服務端的連接,若要實現多客戶端操作,需要涉及到多線程,只要你把每個接收到的Socket對象單獨開一條線程操作,然后用一個死循環while(true)去監聽端口就行,這邊直接給代碼了

線程操作類:SocketThread.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * Socket多線程處理類 用來處理服務端接收到的客戶端請求(處理Socket對象)
 */
public class SocketThread extends Thread {
    private Socket socket;

    public SocketThread(Socket socket) {
        this.socket = socket;
    }

    public void run() {
        // 根據輸入輸出流和客戶端連接
        try {
            InputStream inputStream = socket.getInputStream();
            // 得到一個輸入流,接收客戶端傳遞的信息
            InputStreamReader inputStreamReader = new InputStreamReader(
                    inputStream);// 提高效率,將自己字節流轉為字符流
            BufferedReader bufferedReader = new BufferedReader(
                    inputStreamReader);// 加入緩沖區
            String temp = null;
            String info = "";
            while ((temp = bufferedReader.readLine()) != null) {
                info += temp;
                System.out.println("已接收到客戶端連接");
                System.out.println("服務端接收到客戶端信息:" + info + ",當前客戶端ip為:"
                        + socket.getInetAddress().getHostAddress());
            }

            OutputStream outputStream = socket.getOutputStream();// 獲取一個輸出流,向服務端發送信息
            PrintWriter printWriter = new PrintWriter(outputStream);// 將輸出流包裝成打印流
            printWriter.print("你好,服務端已接收到您的信息");
            printWriter.flush();
            socket.shutdownOutput();// 關閉輸出流

            // 關閉相對應的資源
            bufferedReader.close();
            inputStream.close();
            printWriter.close();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

服務端類:Server.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

    /**
     * Socket服務端
     */
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8888);
            System.out.println("服務端已啟動,等待客戶端連接..");

            while (true) {
                Socket socket = serverSocket.accept();// 偵聽並接受到此套接字的連接,返回一個Socket對象
                SocketThread socketThread = new SocketThread(socket);
                socketThread.start();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

客戶端類:Client.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;


public class Client {

    /**
     * Socket客戶端
     */
    public static void main(String[] args) {
        try {
            //創建Socket對象
            Socket socket=new Socket("localhost",8888);
            
            //根據輸入輸出流和服務端連接
            OutputStream outputStream=socket.getOutputStream();//獲取一個輸出流,向服務端發送信息
            PrintWriter printWriter=new PrintWriter(outputStream);//將輸出流包裝成打印流
            printWriter.print("服務端你好,我是客戶1");
            printWriter.flush();
            socket.shutdownOutput();//關閉輸出流
            
            InputStream inputStream=socket.getInputStream();//獲取一個輸入流,接收服務端的信息
            InputStreamReader inputStreamReader=new InputStreamReader(inputStream);//包裝成字符流,提高效率
            BufferedReader bufferedReader=new BufferedReader(inputStreamReader);//緩沖區
            String info="";
            String temp=null;//臨時變量
            while((temp=bufferedReader.readLine())!=null){
                info+=temp;
                System.out.println("客戶端接收服務端發送信息:"+info);
            }
            
            //關閉相對應的資源
            bufferedReader.close();
            inputStream.close();
            printWriter.close();
            outputStream.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

看下效果實現圖:

 

這里只是拋磚引玉,在實際開發中,基於Socket編程,一般傳遞的並非字符串,很多情況下是對象,我們可以使用ObjectOutputStream將輸出流對象序列化。

例如:

OutputStream outputStream = socket.getOutputStream();
ObjectOutputStream objectOutputStream=new ObjectOutputStream(outputStream);
User user=new User("admin","123456");
objectOutputStream.writeObject(user);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM