當前位置: 首頁> 最新文章列表> socket_export_stream和fread函數如何配合讀取數據?實戰示例詳解

socket_export_stream和fread函數如何配合讀取數據?實戰示例詳解

gitbox 2025-08-30

1. 理解socket_export_stream 函數

socket_export_stream函數的作用是將一個原始的socket 資源轉換成一個可以與標準PHP 流函數兼容的流資源。它使得底層的socket 連接能夠和像fread這樣的流讀取函數一起工作,從而使得數據的讀取更為方便。

 <span><span>resource </span><span><span class="hljs-title function_ invoke__">socket_export_stream</span></span><span> ( resource </span><span><span class="hljs-variable">$socket</span></span><span> )
</span></span>

返回值是一個標準的流資源,這樣你就可以使用fread , fwrite或者其他流操作函數來讀取或寫入數據。

2. 理解fread 函數

fread是用於從文件指針或流中讀取指定字節數數據的函數。它常與fopensocket_export_stream等配合使用,用於讀取流中的數據。

 <span><span><span class="hljs-keyword">string</span></span><span> </span><span><span class="hljs-title function_ invoke__">fread</span></span><span> ( resource </span><span><span class="hljs-variable">$handle</span></span><span> , </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$length</span></span><span> )
</span></span>

參數:

  • $handle是流的資源,可以是socket_export_stream返回的流資源。

  • $length是要讀取的字節數。

fread會返回讀取的內容,如果讀取不到數據,它會返回一個空字符串。

3. 實戰示例:客戶端與服務器的數據讀取

我們將創建一個簡單的TCP 客戶端與服務器通信的實例。客戶端會連接到服務器,通過socket 發送請求,並使用fread從服務器讀取響應。

3.1 創建服務器端代碼

<span><span><span class="hljs-comment">// 服務器端代碼</span></span><span>
</span><span><span class="hljs-variable">$host</span></span><span> = </span><span><span class="hljs-string">'127.0.0.1'</span></span><span>;
</span><span><span class="hljs-variable">$port</span></span><span> = </span><span><span class="hljs-number">8080</span></span><span>;

</span><span><span class="hljs-comment">// 創建 socket 資源</span></span><span>
</span><span><span class="hljs-variable">$server</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_create</span></span><span>(AF_INET, SOCK_STREAM, SOL_TCP);
</span><span><span class="hljs-title function_ invoke__">socket_bind</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>, </span><span><span class="hljs-variable">$host</span></span><span>, </span><span><span class="hljs-variable">$port</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">socket_listen</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>);

</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"服務器已啟動,等待客戶端連接...\n"</span></span><span>;

</span><span><span class="hljs-comment">// 等待客戶端連接</span></span><span>
</span><span><span class="hljs-variable">$client</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_accept</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>);

</span><span><span class="hljs-comment">// 向客戶端發送數據</span></span><span>
</span><span><span class="hljs-variable">$message</span></span><span> = </span><span><span class="hljs-string">"Hello from server!"</span></span><span>;
</span><span><span class="hljs-title function_ invoke__">socket_write</span></span><span>(</span><span><span class="hljs-variable">$client</span></span><span>, </span><span><span class="hljs-variable">$message</span></span><span>, </span><span><span class="hljs-title function_ invoke__">strlen</span></span><span>(</span><span><span class="hljs-variable">$message</span></span><span>));

</span><span><span class="hljs-comment">// 關閉連接</span></span><span>
</span><span><span class="hljs-title function_ invoke__">socket_close</span></span><span>(</span><span><span class="hljs-variable">$client</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">socket_close</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>);
</span></span>

3.2 創建客戶端代碼

<span><span><span class="hljs-comment">// 客戶端代碼</span></span><span>
</span><span><span class="hljs-variable">$host</span></span><span> = </span><span><span class="hljs-string">'127.0.0.1'</span></span><span>;
</span><span><span class="hljs-variable">$port</span></span><span> = </span><span><span class="hljs-number">8080</span></span><span>;

</span><span><span class="hljs-comment">// 創建 socket 資源</span></span><span>
</span><span><span class="hljs-variable">$socket</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_create</span></span><span>(AF_INET, SOCK_STREAM, SOL_TCP);
</span><span><span class="hljs-title function_ invoke__">socket_connect</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>, </span><span><span class="hljs-variable">$host</span></span><span>, </span><span><span class="hljs-variable">$port</span></span><span>);

</span><span><span class="hljs-comment">// 將 socket 資源转换为流資源</span></span><span>
</span><span><span class="hljs-variable">$stream</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_export_stream</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>);

</span><span><span class="hljs-comment">// 從流中讀取數據</span></span><span>
</span><span><span class="hljs-variable">$response</span></span><span> = </span><span><span class="hljs-title function_ invoke__">fread</span></span><span>(</span><span><span class="hljs-variable">$stream</span></span><span>, </span><span><span class="hljs-number">1024</span></span><span>);  </span><span><span class="hljs-comment">// 讀取最多 1024 字節數據</span></span><span>

</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"服務器響應: "</span></span><span> . </span><span><span class="hljs-variable">$response</span></span><span> . </span><span><span class="hljs-string">"\n"</span></span><span>;

</span><span><span class="hljs-comment">// 關閉連接</span></span><span>
</span><span><span class="hljs-title function_ invoke__">fclose</span></span><span>(</span><span><span class="hljs-variable">$stream</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">socket_close</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>);
</span></span>

4. 代碼解析

  • 服務器端:首先,我們創建了一個TCP socket 並綁定到本地地址和端口8080。服務器會在等待客戶端連接的狀態下監聽。當有客戶端連接時,它會接受連接並發送一條消息,然後關閉連接。

  • 客戶端:客戶端首先創建一個TCP socket,並連接到服務器。然後,使用socket_export_stream將socket 轉換為流資源。接著,我們通過fread函數讀取從服務器返回的數據。

5. 常見問題與註意事項

5.1 數據讀取不完全

在網絡編程中,讀取數據時常常遇到的問題是數據讀取不完全。比如,服務器發送的數據量可能遠大於一次讀取的字節數。這時你需要做一些數據拼接工作,直到讀取到所有的數據。

 <span><span><span class="hljs-variable">$response</span></span><span> = </span><span><span class="hljs-string">''</span></span><span>;
</span><span><span class="hljs-keyword">while</span></span><span> (!</span><span><span class="hljs-title function_ invoke__">feof</span></span><span>(</span><span><span class="hljs-variable">$stream</span></span><span>)) {
    </span><span><span class="hljs-variable">$chunk</span></span><span> = </span><span><span class="hljs-title function_ invoke__">fread</span></span><span>(</span><span><span class="hljs-variable">$stream</span></span><span>, </span><span><span class="hljs-number">1024</span></span><span>);  </span><span><span class="hljs-comment">// 每次讀取 1024 位元組</span></span><span>
    </span><span><span class="hljs-variable">$response</span></span><span> .= </span><span><span class="hljs-variable">$chunk</span></span><span>;
}
</span></span>

5.2 非阻塞模式

PHP 的socket 默認是阻塞的,也就是說, fread可能會一直等到數據完全到達才返回。如果需要非阻塞式的讀取數據,可以使用socket_set_nonblock設置socket 為非阻塞模式,這樣fread就會立即返回,即使數據還未完全讀取。

 <span><span><span class="hljs-title function_ invoke__">socket_set_nonblock</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>);
</span></span>

6. 總結

通過socket_export_streamfread函數,我們能夠更加方便地操作socket 數據流。這兩個函數結合使用,可以讓我們像操作文件流一樣簡單地讀取來自遠程服務器的網絡數據。在實際的開發中,這種方式非常適合處理實時、持續的數據交互。

希望通過本文的示例,你能更好地理解如何將這兩個函數結合起來進行實際開發,處理從socket 獲取的數據。