欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?Socket編程從零到實戰(zhàn)詳解(完整實戰(zhàn)案例)

 更新時間:2025年04月12日 10:06:42   作者:北嶺敲鍵盤的荒漠貓  
這篇文章主要介紹了Java?Socket編程從零到實戰(zhàn)詳解,本文給大家介紹的非常詳細,感興趣的朋友一起看看吧

一、Socket基礎(chǔ)概念與工作流程(圖解)

(先理解“打電話”模型,再寫代碼)

1. Socket通信核心模型

關(guān)鍵角色

  • 客戶端:主動發(fā)起連接(類似撥打電話)
  • 服務端:監(jiān)聽端口,等待連接(類似待機電話)
  • Socket對象:連接建立后的數(shù)據(jù)傳輸通道(通話線路)

2. 核心流程分解

  • 服務端:創(chuàng)建ServerSocket → 綁定端口 → 阻塞等待連接(accept()
  • 客戶端:創(chuàng)建Socket → 指定服務端IP和端口 → 發(fā)起連接
  • 雙向通信:通過輸入流(InputStream)和輸出流(OutputStream)收發(fā)數(shù)據(jù)
  • 關(guān)閉連接:調(diào)用close()釋放資源

二、服務端與客戶端基礎(chǔ)代碼分步解析

(每行代碼加注釋,新手必看)

1. 服務端基礎(chǔ)代碼(單線程版)

// 步驟1:創(chuàng)建ServerSocket,綁定端口8080
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服務端啟動,等待連接...");
// 步驟2:等待客戶端連接(阻塞方法,直到有客戶端連接)
Socket clientSocket = serverSocket.accept(); 
System.out.println("客戶端接入:" + clientSocket.getRemoteSocketAddress());
// 步驟3:獲取輸入流(接收客戶端數(shù)據(jù))
InputStream input = clientSocket.getInputStream();
byte[] buffer = new byte[1024];
int len = input.read(buffer);  // 讀取數(shù)據(jù)到buffer數(shù)組
String receivedData = new String(buffer, 0, len);
System.out.println("收到消息:" + receivedData);
// 步驟4:發(fā)送響應數(shù)據(jù)
OutputStream output = clientSocket.getOutputStream();
output.write("已收到!".getBytes());
// 步驟5:關(guān)閉連接(實際開發(fā)中需在finally塊處理)
clientSocket.close();
serverSocket.close();

2. 客戶端基礎(chǔ)代碼

// 步驟1:連接服務端(IP+端口)
Socket socket = new Socket("127.0.0.1", 8080);
System.out.println("連接服務端成功!");
// 步驟2:發(fā)送數(shù)據(jù)
OutputStream output = socket.getOutputStream();
output.write("你好,服務端!".getBytes());
// 步驟3:接收響應
InputStream input = socket.getInputStream();
byte[] buffer = new byte[1024];
int len = input.read(buffer);
String response = new String(buffer, 0, len);
System.out.println("服務端響應:" + response);
// 步驟4:關(guān)閉連接
socket.close();

三、超時設(shè)置詳解(解決卡死問題)

(必學技能,避免程序無限等待)

1. 連接超時(防止無法連接時卡死)

Socket socket = new Socket();
// 設(shè)置連接超時為5秒(單位:毫秒)
socket.connect(new InetSocketAddress("127.0.0.1", 8080), 5000);  // 
  • 觸發(fā)場景:服務端未啟動或網(wǎng)絡不通
  • 異常處理:捕獲SocketTimeoutException提示用戶檢查網(wǎng)絡

2. 讀取超時(防止數(shù)據(jù)未到達時阻塞)

socket.setSoTimeout(3000);  // 設(shè)置讀取超時3秒 
  • 作用范圍InputStream.read()操作
  • 異常處理:超時后拋出SocketTimeoutException,可重試或終止

3. 完整超時處理示例

try (Socket socket = new Socket()) {
    // 連接超時5秒
    socket.connect(new InetSocketAddress("127.0.0.1", 8080), 5000);
    // 讀取超時3秒
    socket.setSoTimeout(3000);
    InputStream input = socket.getInputStream();
    // 讀取數(shù)據(jù)...
} catch (SocketTimeoutException e) {
    System.err.println("操作超時:" + e.getMessage());
} catch (IOException e) {
    System.err.println("連接失?。? + e.getMessage());
}

四、心跳機制實現(xiàn)(維持長連接)

(防止長時間無數(shù)據(jù)導致連接斷開)

1. 心跳包原理

  • 作用:定時發(fā)送空數(shù)據(jù)包,告知對方連接存活
  • 實現(xiàn)方式:客戶端定時任務 + 服務端超時檢測

2. 客戶端心跳代碼

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        try {
            OutputStream out = socket.getOutputStream();
            out.write(0);  // 發(fā)送心跳包(內(nèi)容可為任意約定標識)
            out.flush();
            System.out.println("心跳發(fā)送成功");
        } catch (IOException e) {
            System.err.println("心跳發(fā)送失敗,連接已斷開");
            timer.cancel();  // 停止定時任務
        }
    }
}, 0, 30000);  // 立即啟動,每30秒執(zhí)行一次 

3. 服務端檢測心跳

socket.setSoTimeout(45000);  // 超時時間略大于心跳間隔
try {
    InputStream in = socket.getInputStream();
    while (true) {
        int data = in.read();  // 阻塞等待數(shù)據(jù)
        if (data == 0) {
            System.out.println("收到心跳包");
        }
    }
} catch (SocketTimeoutException e) {
    System.err.println("心跳超時,連接斷開");
    socket.close();
}

五、完整實戰(zhàn)案例:帶超時與心跳的Echo服務

服務端代碼(多線程版)

public class EchoServer {
    public static void main(String[] args) throws IOException {
        ExecutorService pool = Executors.newCachedThreadPool();  // 線程池處理并發(fā)
        try (ServerSocket server = new ServerSocket(8080)) {
            System.out.println("服務端啟動,端口8080");
            while (true) {
                Socket client = server.accept();
                client.setSoTimeout(45000);  // 設(shè)置讀取超時45秒 
                pool.submit(() -> handleClient(client));
            }
        }
    }
    private static void handleClient(Socket client) {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
             PrintWriter out = new PrintWriter(client.getOutputStream(), true)) {
            String input;
            while ((input = in.readLine()) != null) {
                if ("HEARTBEAT".equals(input)) {  // 識別心跳包
                    System.out.println("收到心跳包");
                    continue;
                }
                out.println("Echo: " + input);  // 回顯消息
            }
        } catch (SocketTimeoutException e) {
            System.err.println("客戶端超時未響應,連接關(guān)閉");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try { client.close(); } catch (IOException e) {}
        }
    }
}

客戶端代碼(帶心跳與超時)

public class EchoClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket()) {
            // 連接超時5秒
            socket.connect(new InetSocketAddress("127.0.0.1", 8080), 5000);
            // 讀取超時3秒
            socket.setSoTimeout(3000);
            // 啟動心跳線程(每30秒一次)
            startHeartbeat(socket.getOutputStream());
            Scanner scanner = new Scanner(System.in);
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while (true) {
                System.out.print("輸入消息:");
                String msg = scanner.nextLine();
                out.println(msg);  // 發(fā)送消息
                System.out.println("服務端響應:" + in.readLine());
            }
        } catch (SocketTimeoutException e) {
            System.err.println("操作超時:" + e.getMessage());
        } catch (IOException e) {
            System.err.println("連接異常:" + e.getMessage());
        }
    }
    private static void startHeartbeat(OutputStream out) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    out.write("HEARTBEAT\n".getBytes());  // 發(fā)送心跳標識
                    out.flush();
                } catch (IOException e) {
                    timer.cancel();
                }
            }
        }, 0, 30000);
    }
}

六、常見問題與解決方案速查表

問題現(xiàn)象可能原因解決方案
Connection refused服務端未啟動或端口錯誤檢查服務端代碼是否運行,確認端口一致
Read timed out網(wǎng)絡延遲或服務端未及時響應增加超時時間或優(yōu)化服務端代碼
Broken pipe連接已關(guān)閉仍嘗試寫數(shù)據(jù)發(fā)送前檢查socket.isClosed(),捕獲異常后重連
內(nèi)存泄漏未關(guān)閉Socket或流使用try-with-resources自動關(guān)閉資源

七、Java Socket核心方法速查表

方法名所屬類功能描述參數(shù)說明返回值常見異常使用示例
ServerSocket(int port)ServerSocket創(chuàng)建服務端Socket并綁定指定端口port:監(jiān)聽的端口號(0-65535)BindException(端口被占用)new ServerSocket(8080);
accept()ServerSocket阻塞等待客戶端連接,返回通信用的Socket對象Socket(客戶端連接對象)IOExceptionSocket client = serverSocket.accept();
close()ServerSocket關(guān)閉服務端Socket,釋放端口資源IOExceptionserverSocket.close();
Socket(String host, int port)Socket客戶端主動連接服務端(構(gòu)造函數(shù)隱式調(diào)用connect()host:服務端IP;port:服務端端口UnknownHostException, IOExceptionSocket socket = new Socket("127.0.0.1", 8080);
connect(SocketAddress addr, int timeout)Socket顯式連接服務端,可設(shè)置超時時間addr:服務端地址;timeout:超時毫秒SocketTimeoutExceptionsocket.connect(new InetSocketAddress("127.0.0.1", 8080), 5000);
getInputStream()Socket獲取輸入流,用于接收數(shù)據(jù)InputStreamIOExceptionInputStream in = socket.getInputStream();
getOutputStream()Socket獲取輸出流,用于發(fā)送數(shù)據(jù)OutputStreamIOExceptionOutputStream out = socket.getOutputStream();
setSoTimeout(int timeout)Socket設(shè)置讀取超時時間(單位:毫秒),超時后拋出SocketTimeoutExceptiontimeout:超時時間(0表示無限等待)SocketExceptionsocket.setSoTimeout(3000);
setKeepAlive(boolean on)Socket啟用/禁用TCP?;顧C制(默認關(guān)閉),自動檢測連接是否存活on:true啟用,false禁用SocketExceptionsocket.setKeepAlive(true);
shutdownOutput()Socket關(guān)閉輸出流(發(fā)送FIN包),通知對方數(shù)據(jù)發(fā)送完畢,但不關(guān)閉SocketIOExceptionsocket.shutdownOutput();
close()Socket關(guān)閉Socket連接,釋放資源IOExceptionsocket.close();
readInt()DataInputStream從輸入流讀取4字節(jié)的int值(常用于解析長度頭)intEOFException, IOExceptionint length = new DataInputStream(in).readInt();
writeInt(int v)DataOutputStream向輸出流寫入4字節(jié)的int值(常用于發(fā)送長度頭)v:要寫入的整數(shù)值IOExceptionnew DataOutputStream(out).writeInt(1024);

到此這篇關(guān)于Java Socket編程從零到實戰(zhàn)詳解的文章就介紹到這了,更多相關(guān)Java Socket編程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java數(shù)據(jù)結(jié)構(gòu)學習之樹

    Java數(shù)據(jù)結(jié)構(gòu)學習之樹

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)學習之樹,文中有非常詳細的代碼示例,對正在學習java數(shù)據(jù)結(jié)構(gòu)的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-05-05
  • intellij idea 2021.2 打包并上傳運行spring boot項目的詳細過程(spring boot 2.5.4)

    intellij idea 2021.2 打包并上傳運行spring boot項目的詳細過程(spring boot 2

    這篇文章主要介紹了intellij idea 2021.2 打包并上傳運行一個spring boot項目(spring boot 2.5.4),本文通過圖文并茂的形式給大家介紹的非常詳細,需要的朋友可以參考下
    2021-09-09
  • java 單例模式容易忽略的細節(jié)

    java 單例模式容易忽略的細節(jié)

    這篇文章主要介紹了java 單例模式容易忽略的細節(jié),幫助大家更好的理解和使用java 單例模式,感興趣的朋友可以了解下
    2020-12-12
  • Java 實現(xiàn)LZ78壓縮算法的示例代碼

    Java 實現(xiàn)LZ78壓縮算法的示例代碼

    這篇文章主要介紹了Java 實現(xiàn)LZ78壓縮算法的示例代碼,代碼簡單易懂,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-05-05
  • 淺談Arrays.asList() 和ArrayList類型區(qū)別

    淺談Arrays.asList() 和ArrayList類型區(qū)別

    下面小編就為大家?guī)硪黄狝rrays.asList() 和ArrayList類型區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10
  • 最新評論