簡體   English   中英

使用tcp從PHP發送到JAVA后,數據已損壞

[英]Data is corrupted after sending from PHP to JAVA using tcp

我正在嘗試將數據從PHP TCP服務器發送到JAVA TCP客戶端。 我正在通過比較數據的十六進制值來比較我的結果。

PHP腳本讀取STDIN,通過套接字一次將其發送一個字節,而Java使用DataInputStream.read()讀取它,轉換為十六進制並顯示。

如果我手動在腳本中輸入數據-可以。 如果我將文件與數據一起使用-可以正常工作,但是當我分配/ dev / urandom(甚至幾個字節)時-Java端的數據已損壞。 隨機位置總是有十六進制值efbfbd而不是正確的數據。 請幫我解決這個問題。 PHP代碼:

$f = fopen( 'php://stdin', 'rb' );
while($line = fread($f, 1)){

    $length = 1;
    echo bin2hex($line)."\n";
    echo socket_write($client, $line, 1)."\n";

     $sent = socket_write($client, $line, $length);

if ($sent === false) {

    break;
}

// Check if the entire message has been sented
if ($sent < $length) {

    // If not sent the entire message.
    // Get the part of the message that has not yet been sented as message
    $line = substr($line, $sent);

    // Get the length of the not sented part
    $length -= $sent;

}

Java代碼:

in = new DataInputStream(clientSocket.getInputStream());

            byte[] data = new byte[1];

            int count = 0;
            while(in.available() > 0){
                //System.out.println(in.available());
                     in.read(data);
                String message = new String(data);

                System.out.println(message);
                //System.out.flush();

                System.out.println( toHex(message) );
                //in.flush();
                message = "";



            }

您正在嘗試編碼。 通過調用new String(data) ,無論使用哪種編碼方式,字節數組都將使用默認編碼轉換為字符串(例如,可以通過java -Dfile.encoding=UTF-8將編碼設置為UTF-8 )。

您想要的Java代碼很可能看起來如下所示:

    in = new DataInputStream(clientSocket.getInputStream());

    byte[] data = new byte[1];

    int count = 0;
    while (in.available() > 0) {
        // System.out.println(in.available());
        in.read(data);
        String hexMessage = Integer.toHexString(data[0] & 0xFF);
        String stringMessage = new String(data, "UTF-8"); // US-ASCII, ISO-8859-1, ...
        System.out.println(hexMessage);
    }

更新:我錯過了32位問題。 用Java簽名的8位byte被符號擴展為32位int 要有效撤消此符號擴展,可以使用0xFF屏蔽byte

Java程序存在兩個主要問題。

首先-使用in.available() 它不會告訴您消息中還有多少字節。 它只是說出流中准備好多少字節並可供讀取而不會被阻塞。 例如,如果服務器通過套接字發送了兩個數據包,一個已經到達,但是一個仍在通過Internet發送,每個數據包有200個字節(這只是一個例子),那么在第一個調用中,會得到答案200 如果讀取200個字節,則確保不會被阻止。 但是,如果第二個數據包尚未到達,則您對in.available()下一次檢查將返回0 如果此時停止,則只有一半的數據。 不是您想要的。

通常,您要么必須閱讀直到到達流末尾( InputStream.read()返回-1),然后您就不能再使用相同的流並關閉套接字了,或者您有一個特定的協議告訴您您期望多少個字節,然后讀取該字節數。


但這不是在程序輸出中看到奇怪值的原因。 原因是Java和PHP表示字符串的方式完全不同。 在PHP中,字符串完全可以包含任何字節,並且將它們解釋為字符取決於程序設計師。

這基本上意味着,PHP字符串等效於Java中的byte[]

但是Java字符串完全不同。 它在內部由char數組組成,並且char在UTF-16編碼中始終為兩個字節。 當您將字節轉換為Java String ,總是通過使用某些字符編碼對字節進行編碼來完成的,以便將適當的字符存儲在字符串中。

例如,如果你的字節是44 4F 4C 4C ,和字符編碼是ISO-8859-1,這將被解釋為字符\D\O\L\L 這將是一個包含四個字符的字符串- "DOLL" 但是,如果您的字符編碼為UTF-16 ,則字節將被解釋為\䑏\䱌 只有兩個字符的字符串"䑏䱌"

從控制台或文件中讀取數據時,默認情況下,數據可能采用Java期望的編碼。 通常情況下,文件是用純英文書寫的,只有英文字母,空格和標點符號。 這些都是7位字符,在ISO-8859-1和UTF-8中是相同的,這是常見的默認設置。 但是在/dev/urandom您會有一些字節,范圍在80FF ,當解釋為UTF-16 Java字符串時,可能會有所不同。

此外,您沒有在Java中顯示toHex()方法。 它可能會再次從字符串中讀取字節,但是使用哪種編碼? 如果您使用ISO-8859-1將字節讀取到String ,並以UTF-8讀取它們,則將獲得完全不同的字節。

如果您想確切地了解PHP發送給您的內容,請不要將字節放在String 編寫一個適用於字節數組的toHex方法,並使用直接讀取的byte[]


另外,請始終記住檢查read()返回的字節數,並僅解釋該字節數! read() 並不總是填充整個陣列。 因此,在新的toHex()方法中,您還需要將讀取的字節數作為參數傳遞,這樣它就不會在它們后面顯示數組的各個部分。 在您的情況下,您只有一個一字節的數組-不建議這樣做-但即使在這種情況下, read()可以返回0,這是一個完全合法的值,表明在對read()特定調用中沒有字節可用,盡管下一個read()可能有一些可用。

正如上面的評論所述,您可能在字節的字符串表示形式方面遇到了麻煩String message = new String(data); 可以肯定的是,您應該獲取數據字節並將其編碼為例如Base64。 您可以使用諸如Apache CommonsJava 8之類的庫來實現。 您應該能夠在PHP中進行類似的操作以進行比較。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM