首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 與 Java Servlet 基於 Socket 的跨語言通信實戰

     編輯:PHP 相關知識

架構設計

  • Client:PHP 腳本 (CLI 或 Web)
  • Server:Java Servlet 容器 (Tomcat) 啟動時啟動 Socket 監聽線程
  • 協議:TCP 長連接,文本行協議,以 \r\n (CRLF) 結束

Server 端關鍵點:避免阻塞 Tomcat 啟動

錯誤做法:在 Servlet.init() 中直接 while(true) server.accept() → 導致 Tomcat 啟動超時。

正確做法:init() 中啟動獨立線程,線程內循環 accept(),每個連接再派生工作線程處理。

Servlet 入口類

@WebServlet(name = "SocketServlet", loadOnStartup = 0)
public class SocketServlet extends HttpServlet {
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        new Thread(() -> {
            try (ServerSocket server = new ServerSocket(4700)) {
                while (true) {
                    Socket socket = server.accept();
                    new SocketHandler(socket).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

工作線程處理業務

class SocketHandler extends Thread {
    private final Socket socket;
    SocketHandler(Socket s) { this.socket = s; }

    @Override
    public void run() {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {

            String line = in.readLine(); // 阻塞直到 \r\n
            System.out.println("Received: " + line);

            out.println("server send"); // 自動 flush + \r\n
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try { socket.close(); } catch (IOException ignored) {}
        }
    }
}

Client 端 PHP 代碼

<?php
$userName = 'veverrr';
$password = 'SWJTU';
$host = 'localhost';
$port = 4700;

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!$socket) die("socket_create failed: " . socket_strerror(socket_last_error()));

$conn = @socket_connect($socket, $host, $port);
if (!$conn) die("socket_connect failed: " . socket_strerror(socket_last_error($socket)));

// 關鍵:發送數據必須以 \r\n 結束,對應 Java readLine()
$payload = $userName . $password . "\r\n";
socket_write($socket, $payload, strlen($payload));

$response = socket_read($socket, 1024);
echo "Server reply: $response";

socket_close($socket);

核心坑點總結

問題原因解決
Java readLine() 永久阻塞PHP 發送缺少 \r\nPHP 端拼接 chr(13).chr(10) 或 "\r\n"
Java 無收到數據PrintWriter 未 flush()構造 new PrintWriter(out, true) 自動行刷新
Tomcat 啟動卡死主線程阻塞於 accept()改為獨立線程監聽
中文亂碼編碼不一致雙方統一指定 UTF-8 的 InputStreamReader/OutputStreamWriter

生產環境建議

  • 引入長連接心跳機制,防止防火牆斷開空閒連接。
  • 序列化協議升級為 JSON/Protobuf,替代簡單文本行。
  • Server 端使用線程池 (ExecutorService) 替代無限創建線程。
  • PHP 端封裝為可復用類,支持超時、重試、異常處理。
  • 考慮更成熟的 RPC 框架:gRPC, Thrift, Hessian, 或消息隊列 RabbitMQ/Kafka。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved