首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Java Socket 客戶端與 Python Socket 客戶端的差異解析

     編輯:程式設計疑難解答

問題背景

在專案開發中,我們有一個使用 Java 編寫的 Server 端,僅持有其文檔且已使用 Java 實現客戶端。現在需將客戶端移植至 Python,但在傳輸協議處理上遇到阻礙,導致 Server 無法接收 Python 發送的數據包。

Java 實現代碼分析

原始 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 實現嘗試與問題

初始 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) 完全對應。

總結

  • Java short 固定 2 字節,Python int 長度可變,需顯式指定打包格式
  • 網絡傳輸統一使用大端序(Network Byte Order)
  • Python 中處理二進制協議時,struct 模組是標準工具,避免手動位運算構造 bytes

修正後 Python 客戶端即可與 Java Server 正常通訊,問題圓滿解決。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved