Java的Socket通訊簡單例項

qch發表於2021-10-27

  前言

  Java網路程式設計之Socket套接字,Socket套接字使用TCP提供了兩臺計算機之間的通訊機制

  TCP(英語:Transmission Control Protocol,傳輸控制協議) 是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協議,TCP 層是位於 IP 層之上,應用層之下的中間層。TCP 保障了兩個應用程式之間的可靠通訊。通常用於網際網路協議,被稱 TCP / IP

  本文記錄Java的Socket通訊簡單例項

 

  服務端

package cn.huanzi.qch.util;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Socket服務端
 */
public class SocketServer {
    public static void main(String[] args) throws Exception{
        //服務端在20006埠監聽客戶端請求的TCP連線
        ServerSocket server = new ServerSocket(20086);
        Socket client;

        System.out.println("服務端啟動成功!");

        //如果使用多執行緒,那就需要執行緒池,防止併發過高時建立過多執行緒耗盡資源
        ExecutorService threadPool = Executors.newFixedThreadPool(10);

        while (true) {
            //等待客戶端的連線,如果沒有獲取連線
            client = server.accept();

            //為每個客戶端連線開啟一個執行緒
            threadPool.submit(new ServerThread(client));
        }
    }
}

/**
 * 與客戶端連線操作非同步執行緒
 */
class ServerThread implements Runnable {
    //socket連線
    private final Socket client;

    public ServerThread(Socket client){
        this.client = client;
    }

    @Override
    public void run() {
        try{
            System.out.println("與客戶端["+client.getInetAddress()+":"+client.getPort()+"]連線成功!");

            //獲取Socket的輸出流,用來向客戶端傳送資料
            PrintStream out = new PrintStream(client.getOutputStream());
            //獲取Socket的輸入流,用來接收從客戶端傳送過來的資料
            BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));

            boolean flag =true;
            while(flag){
                //接收從客戶端傳送過來的資料
                String msg = buf.readLine();

                //約定:通過約定符號'exit'通知服務端關閉與客戶端的連線
                if("exit".equals(msg)){
                    flag = false;
                }else{
                    //將接收到的字串前面加上echo,傳送到對應的客戶端
                    out.println("echo:"+msg);
                }
                System.out.println("收到客戶端["+client.getInetAddress()+":"+client.getPort()+"]訊息:"+msg);
            }

            System.out.println("與客戶端["+client.getInetAddress()+":"+client.getPort()+"]斷開連線...");

            out.close();
            buf.close();
            client.close();
        }catch(Exception e){
            System.err.println("Socket連線異常...");
            e.printStackTrace();
        }
    }
}

 

  客戶端

package cn.huanzi.qch.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;

/**
 * Socket客戶端
 */
public class SocketClient {
    //地址
    private static final String host = "127.0.0.1";

    //
    private static final int port = 20086;

    //Socket連線
    private static Socket client;

    //Socket的輸出流,用來傳送資料到服務端
    private static PrintStream out;

    //Socket的輸入流,用來接收從服務端傳送過來的資料
    private static BufferedReader buf;

    /**
     * 初始化Socket連線
     */
    private static void init() throws IOException {
        //客戶端請求與 host 在 port 埠建立TCP連線
        client = new Socket(host, port);
        //獲取Socket的輸出流
        out = new PrintStream(client.getOutputStream());
        //獲取Socket的輸入流
        buf = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));
    }

    /**
     * 傳送訊息
     */
    private static void sendMsg(String msg) throws IOException {
        try{
            //傳送資料到服務端
            out.println(msg);
        }catch (Exception e){
            //列印日誌,並重連Socket
            System.err.println("Socket連線異常,正在重新連線...");
            e.printStackTrace();

            init();

            //重新傳送資料資料到服務端
            out.println(msg);
        }


        //等待服務端響應
        try{
            String echo = buf.readLine();
            System.out.println("收到服務端回應:"+echo);
        }catch(SocketTimeoutException e){
            System.err.println("服務端響應超時...");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("服務端響應異常...");
            e.printStackTrace();
        }
    }

    /**
     * 關閉Socket連線
     * 約定:通過約定符號'exit'通知服務端關閉與客戶端的連線
     */
    private static void close() throws IOException {
        //通知服務端結束與客戶端的連線非同步執行緒
        out.println("exit");

        out.close();
        buf.close();
        client.close();
    }


    public static void main(String[] args) throws IOException, InterruptedException {
        init();

        for (int i = 1; i <= 5; i++) {
            sendMsg("你好,我是訊息"+i);
            Thread.sleep(2000);//休眠
        }

        close();
    }
}

 

  效果

  先執行服務端,再執行客戶端

 

  客戶端

 

  服務端

 

  後記

  為了減少傳輸資料的大小,可以通過約定報文格式,傳輸16進位制資料,例如:OxFF 01 3A 4D

 

  Java的Socket通訊簡單例項暫時先記錄到這,後續再進行補充

相關文章