在專案開發中,我們有一個使用 Java 編寫的 Server 端,僅持有其文檔且已使用 Java 實現客戶端。現在需將客戶端移植至 Python,但在傳輸協議處理上遇到阻礙,導致 Server 無法接收 Python 發送的數據包。
原始 Java 客戶端核心邏輯如下:
public static void main(String[] args) throws WindException, SendException, RecvException {
String host = "172.22.128.16";
int port = 6001;
TcpComm tcp = new TcpComm(true);
try {
tcp.call(host, port);
tcp.setTimeOut(30);
String msg = "POF001|S2B024|01|0033596105||";
byte[] req = msg.getBytes();
tcp.sendMsg(req);
byte[] ans = tcp.recvBytesMsg();
System.out.println(ans);
} catch (CallException e) {
e.printStackTrace();
}
}
關鍵在於 sendMsg 方法中對報文頭的處理:
public void sendMsg(byte[] b) throws SendException {
try {
OutputStream out = sock.getOutputStream();
if (hasAtrHead) {
byte[] sbt = short2Byte((short) b.length, true);
out.write(head);
out.write(sbt);
}
out.write(b);
out.flush();
}
}
其中 short2Byte 方法實現大端序(高位在前)的 short 到 byte 數組轉換:
static public byte[] short2Byte(short value, boolean order) {
byte[] bt = new byte[2];
if (order) { // true 表示大端序
bt[0] = (byte) (value >> 8 & 0xff);
bt[1] = (byte) (value & 0xff);
} else {
bt[1] = (byte) (value >> 8 & 0xff);
bt[0] = (byte) (value & 0xff);
}
return bt;
}
初始 Python 代碼嘗試模擬相同邏輯:
# -*- coding:GBK -*-
import socket
class Comm(object):
def heads(self, length):
bt = bytearray()
bt.append(length >> 8 & 0xff)
bt.append(length & 0xff)
return bt
def client(self):
HOST = '172.22.128.16'
PORT = 6001
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while 1:
content = 'POF001|F2B107|01|3061009458||'
length = len(content)
head = self.heads(length)
content = bytearray(content)
s.send(head)
s.send(content)
data = s.recv(2048)
s.close()
if __name__ == '__main__':
a = Comm()
a.client()
雖然邏輯看似一致,但 Server 端始終未收到數據。經過兩天排查,最終發現根本原因在於 Python 中整數轉換為 bytes 的默認行為差異。
關鍵點: Java 的 short 類型佔 2 字節,而 Python 中直接使用 length >> 8 操作雖能得到正確數值,但構造 bytearray 時需確保輸出為 2 字節的網絡序(大端序)。
正確做法是使用 struct.pack 指定格式字符 '!h'(網絡序 short):
import struct
def heads(self, length):
return struct.pack('!h', length)
!h 含義:! 表示網絡序(大端序),h 表示 signed short(2 字節)。這與 Java 的 short2Byte(value, true) 完全對應。
short 固定 2 字節,Python int 長度可變,需顯式指定打包格式struct 模組是標準工具,避免手動位運算構造 bytes修正後 Python 客戶端即可與 Java Server 正常通訊,問題圓滿解決。