You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java客户端与服务器通信异常:初始数据接收失败求助

问题描述

我明确知道自己存在一处明显错误,但始终无法定位。我正在实现一个客户端(Alice)向服务器(Bob)发送自身identity与nonce的功能,服务器读取后应返回自身nonce,以及经加密的服务器identity;客户端接收后,再向服务器发送自身加密后的identity供其解密。目前遇到的问题是:服务器无法接收客户端发送的初始输入(加密操作前的数据),已确认客户端与服务器连接正常,但服务器无法读取输入。

原始代码

服务器Bob代码

import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.Arrays;

public class Bob {
    public static void main(String[] args) throws Exception {

        String Bobidentity = "Bob";
        
        // Start listening for incoming connections
        int portNumber = 1500;

        ServerSocket serverSocket = new ServerSocket(portNumber);
        System.out.println("Bob waiting for Alice...");

        // Accept Alice's connection
        Socket socket = serverSocket.accept();
        System.out.println("Alice connected.");

        // Get input/output streams
        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());

        // Receive identity and nonce from Alice
        String aliceIdentity = (String) in.readObject();
        int aliceNonce = in.readInt();

        System.out.println("Received Alice Identity (1) " + aliceIdentity);
        System.out.println("Received Alice Nonce (1) " + aliceNonce);


        int bobNonce = 3;

        // Send nonce to Alice
        out.writeInt(bobNonce);

        // Generate shared secret key using both nonces
        byte[] sharedSecretBytes = (Integer.toString(bobNonce) + Integer.toString(aliceNonce)).getBytes();
        SecretKey secretKey = new SecretKeySpec(sharedSecretBytes, "DES");

        // Encrypt and send message to Alice containing Bob's identity and nonce NA
        byte[] messageToAlice = (Bobidentity + "," + aliceNonce).getBytes();
        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encryptedMessage = cipher.doFinal(messageToAlice);
        out.writeObject(encryptedMessage);

        // Receive encrypted message from Alice containing Alice's identity and nonce NB
        byte[] encryptedResponse = (byte[]) in.readObject();

        System.out.println("Encrypted message from Alice (3) " + Arrays.toString(encryptedResponse));

        byte[] decryptedResponse = cipher.doFinal(encryptedResponse);
        String[] parts = new String(decryptedResponse).split(",");
        String aliceIdentityReceived = parts[0];
        int receivedNonce = Integer.parseInt(parts[1]);

        System.out.println("Decrypted Identity from Alice (3) " + aliceIdentityReceived);
        System.out.println("Decrypted Nonce from Alice (3) " + receivedNonce);



        // Close the connection
        socket.close();
        serverSocket.close();
    }
}

客户端Alice代码

import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.Arrays;

public class Alice {
    public static void main(String[] args) throws Exception {
        // Connect to Bob

        String hostName = "localhost";
        int portNumber = 1500;

        //Socket socket = new Socket("localhost", 12345);
        try (
            Socket socket = new Socket(hostName, portNumber);
        ) {

            ObjectOutputStream outt = new ObjectOutputStream(socket.getOutputStream());

            int nonce = 5;
            String identity = "Alice";

            // Send identity and nonce to Bob
            outt.writeObject(identity);
            outt.writeInt(nonce);

            // Receive nonce and encrypted message from Bob
            ObjectInputStream inn = new ObjectInputStream(socket.getInputStream());

                int receivedNonce = inn.readInt();
                byte[] encryptedMessage = (byte[]) inn.readObject();

                System.out.println("Encrypted message from Bob (2) " + Arrays.toString(encryptedMessage));
                System.out.println("Bobs Nonce (2) " + receivedNonce);

                // Generate shared secret key using both nonces
                byte[] sharedSecretBytes = (Integer.toString(nonce) + Integer.toString(receivedNonce)).getBytes();
                SecretKey secretKey = new SecretKeySpec(sharedSecretBytes, "DES");

                // Decrypt and extract Bob's identity and nonce NA
                Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
                cipher.init(Cipher.DECRYPT_MODE, secretKey);
                byte[] decryptedMessage = cipher.doFinal(encryptedMessage);
                String[] parts = new String(decryptedMessage).split(",");
                String bobIdentity = parts[0];
                int bobNonce = Integer.parseInt(parts[1]);

                System.out.println("Decrypted Bobs identity (2) " + bobIdentity);
                System.out.println("Decrypted nonce (2) " + bobNonce);


                // Send encrypted message to Bob containing Alice's identity and nonce NB
                byte[] messageToBob = (identity + "," + receivedNonce).getBytes();
                byte[] encryptedResponse = cipher.doFinal(messageToBob);
                outt.writeObject(encryptedResponse);
                // Close the connection


        }
        catch (UnknownHostException e) {
            System.err.println("Don't know about host " + hostName);
            System.exit(1);
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection to " +
                    hostName);
            System.exit(1);
        }

    }
}
问题定位与修复

核心问题:输出流未刷新,数据滞留在缓冲区

客户端Alice发送identity和nonce后,ObjectOutputStream的缓冲区没有被强制刷新,导致数据没有实际发送到服务器,服务器的in.readObject()一直处于阻塞等待状态。

此外,双方生成共享密钥的顺序不一致,会导致后续解密失败,这也是需要修正的潜在问题。

修复步骤

1. 客户端添加流刷新操作

在客户端Alice发送完初始的identity和nonce后,调用flush()强制缓冲区数据发送:

// Send identity and nonce to Bob
outt.writeObject(identity);
outt.writeInt(nonce);
outt.flush(); // 新增:确保数据立即发送到服务器

2. 统一密钥生成顺序

服务器Bob原本的密钥生成是Bob的nonce + Alice的nonce,而客户端是Alice的nonce + Bob的nonce,两者顺序相反,导致密钥不一致。修改服务器的密钥生成代码,统一为Alice的nonce在前,Bob的nonce在后:

// 服务器Bob修改后的密钥生成代码
byte[] sharedSecretBytes = (Integer.toString(aliceNonce) + Integer.toString(bobNonce)).getBytes();

3. 修正Cipher模式切换问题

客户端在使用Cipher进行解密后,需要重新初始化为加密模式才能进行加密操作,否则会抛出异常:

// 客户端Alice发送加密消息前,重新初始化Cipher为加密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedResponse = cipher.doFinal(messageToBob);

完整修复后的代码

修复版客户端Alice

import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.Arrays;

public class Alice {
    public static void main(String[] args) throws Exception {
        String hostName = "localhost";
        int portNumber = 1500;

        try (Socket socket = new Socket(hostName, portNumber)) {

            ObjectOutputStream outt = new ObjectOutputStream(socket.getOutputStream());

            int nonce = 5;
            String identity = "Alice";

            // Send identity and nonce to Bob
            outt.writeObject(identity);
            outt.writeInt(nonce);
            outt.flush(); // 刷新缓冲区,确保数据发送

            // Receive nonce and encrypted message from Bob
            ObjectInputStream inn = new ObjectInputStream(socket.getInputStream());

            int receivedNonce = inn.readInt();
            byte[] encryptedMessage = (byte[]) inn.readObject();

            System.out.println("Encrypted message from Bob (2) " + Arrays.toString(encryptedMessage));
            System.out.println("Bob's Nonce (2) " + receivedNonce);

            // Generate shared secret key using both nonces
            byte[] sharedSecretBytes = (Integer.toString(nonce) + Integer.toString(receivedNonce)).getBytes();
            SecretKey secretKey = new SecretKeySpec(sharedSecretBytes, "DES");

            // Decrypt and extract Bob's identity and nonce NA
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] decryptedMessage = cipher.doFinal(encryptedMessage);
            String[] parts = new String(decryptedMessage).split(",");
            String bobIdentity = parts[0];
            int bobNonce = Integer.parseInt(parts[1]);

            System.out.println("Decrypted Bob's identity (2) " + bobIdentity);
            System.out.println("Decrypted nonce (2) " + bobNonce);

            // Send encrypted message to Bob containing Alice's identity and nonce NB
            byte[] messageToBob = (identity + "," + receivedNonce).getBytes();
            cipher.init(Cipher.ENCRYPT_MODE, secretKey); // 重新初始化为加密模式
            byte[] encryptedResponse = cipher.doFinal(messageToBob);
            outt.writeObject(encryptedResponse);
            outt.flush();

        } catch (UnknownHostException e) {
            System.err.println("无法识别主机 " + hostName);
            System.exit(1);
        } catch (IOException e) {
            System.err.println("无法建立与 " + hostName + " 的连接I/O");
            System.exit(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

修复版服务器Bob

import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.Arrays;

public class Bob {
    public static void main(String[] args) throws Exception {

        String Bobidentity = "Bob";
        
        int portNumber = 1500;
        ServerSocket serverSocket = new ServerSocket(portNumber);
        System.out.println("Bob等待Alice连接...");

        Socket socket = serverSocket.accept();
        System.out.println("Alice已连接。");

        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());

        // Receive identity and nonce from Alice
        String aliceIdentity = (String) in.readObject();
        int aliceNonce = in.readInt();

        System.out.println("收到Alice的身份 (1) " + aliceIdentity);
        System.out.println("收到Alice的Nonce (1) " + aliceNonce);

        int bobNonce = 3;

        // Send nonce to Alice
        out.writeInt(bobNonce);
        out.flush();

        // Generate shared secret key using both nonces - 统一顺序
        byte[] sharedSecretBytes = (Integer.toString(aliceNonce) + Integer.toString(bobNonce)).getBytes();
        SecretKey secretKey = new SecretKeySpec(sharedSecretBytes, "DES");

        // Encrypt and send message to Alice containing Bob's identity and nonce NA
        byte[] messageToAlice = (Bobidentity + "," + aliceNonce).getBytes();
        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encryptedMessage = cipher.doFinal(messageToAlice);
        out.writeObject(encryptedMessage);
        out.flush();

        // Receive encrypted message from Alice containing Alice's identity and nonce NB
        byte[] encryptedResponse = (byte[]) in.readObject();

        System.out.println("收到Alice的加密消息 (3) " + Arrays.toString(encryptedResponse));

        // 初始化解密模式
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] decryptedResponse = cipher.doFinal(encryptedResponse);
        String[] parts = new String(decryptedResponse).split(",");
        String aliceIdentityReceived = parts[0];
        int receivedNonce = Integer.parseInt(parts[1]);

        System.out.println("解密后的Alice身份 (3) " + aliceIdentityReceived);
        System.out.println("解密后的Nonce (3) " + receivedNonce);

        // Close the connection
        socket.close();
        serverSocket.close();
    }
}

内容的提问来源于stack exchange,提问作者Fabiano Morra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 02:15:55