當前位置: 首頁> 最新文章列表> 使用pack() 結合stream_socket_client() 發送原始數據

使用pack() 結合stream_socket_client() 發送原始數據

M66 2025-06-04

在網絡編程中,有時候我們需要發送原始的二進制數據到遠程服務器,特別是在實現某些協議時。 PHP 提供了非常強大的函數pack() ,可以將數據按照指定格式打包成二進製字符串。結合stream_socket_client() ,我們可以方便地通過TCP 或UDP 連接發送這些原始數據。

本文將詳細介紹如何利用PHP 的pack()函數來打包數據,並通過stream_socket_client()發送給指定服務器。


1. pack() 函數簡介

pack()函數用於把數據轉換成二進製字符串。它的第一個參數是格式字符串,後續參數是要打包的數據。格式字符串中包含各種格式代碼,比如:

  • C — 無符號字符(1 字節)

  • n — 無符號短整型(2 字節,大端序)

  • N — 無符號長整型(4 字節,大端序)

  • a — NUL 字符填充的字符串

  • A — 空格填充的字符串

例如:

 $data = pack('Cnn', 0x01, 300, 400);

這裡的0x01是一個字節, 300400都是2 字節無符號整型。


2. stream_socket_client() 簡介

stream_socket_client()用於創建客戶端的網絡連接,可以支持TCP、UDP 等協議。常用語法如下:

 $socket = stream_socket_client("tcp://m66.net:12345", $errno, $errstr, 30);
  • 第一個參數是地址,格式如tcp://域名:端口

  • 連接成功返回資源,失敗返回false

  • $errno$errstr會返回錯誤碼和錯誤信息

  • 最後一個參數是超時時間(秒)

通過此連接,我們可以使用fwrite()發送數據, fread()接收數據。


3. 示例:用pack() 打包數據並發送

假設我們需要向服務器發送一個協議數據包,格式如下:

  • 1 字節命令碼,固定為0x10

  • 2 字節的用戶ID,大端序

  • 4 字節的時間戳,大端序

  • 8 字節的字符串(如果不足8 字節,空格填充)

PHP 代碼示例:

 <?php

// 目標服務器信息
$host = "m66.net";
$port = 12345;

// 創建 TCP 連接
$socket = stream_socket_client("tcp://$host:$port", $errno, $errstr, 10);
if (!$socket) {
    die("連接失败: $errstr ($errno)\n");
}

// 準備數據
$command = 0x10;
$userId = 1025;
$timestamp = time();
$username = "user123";

// 打包數據
// C - 1字節無符號整數
// n - 2字節無符號短整數(大端)
// N - 4字節無符號長整數(大端)
// A8 - 長度為8的字符串,空格填充
$packedData = pack('CnNA8', $command, $userId, $timestamp, $username);

// 發送數據
fwrite($socket, $packedData);

// 讀取服務器響應(假設服務器會返回 4 字節響應碼)
$response = fread($socket, 4);
if ($response !== false) {
    $responseCode = unpack('N', $response)[1];
    echo "服務器響應碼: $responseCode\n";
} else {
    echo "未接收到服務器響應\n";
}

fclose($socket);

4. 關鍵點總結

  • 使用pack()可以方便地將各種數據類型轉換成二進制數據,適合網絡傳輸。

  • stream_socket_client()用於創建網絡連接,支持多種協議。

  • 發送二進制數據時,確保雙方對協議格式理解一致,特別是數據長度和字節序。

  • 讀取數據時也要用unpack()來解析原始二進制數據。