[英]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
您會有一些字節,范圍在80
到FF
,當解釋為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 Commons或Java 8之類的庫來實現。 您應該能夠在PHP中進行類似的操作以進行比較。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.