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

Java TCP通信异常:客户端收到带乱码前缀的服务器返回值'1'

问题描述

我正在开发一款在线游戏,用TCP实现客户端与服务器通信。客户端发送用户名后,服务器本该返回字符'1',但实际收到的是'�� 1'。已经给服务器和客户端都设置了UTF-8编码,问题依然存在。


服务器代码

package org.example;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;

public class TCPServer {
    static ServerSocket serverSocket;
    public static void main(String[] args) {
        System.out.println("server is running....");

        int port=1234;
        try{
            serverSocket=new ServerSocket(port);
            while (true){
                Socket clientSocket=serverSocket.accept();
                System.out.println("a client connected");
                new ClientHandler(clientSocket).start();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    static class ClientHandler extends Thread{
        private final Socket clientSocket;

        public ClientHandler(Socket socket) {
            this.clientSocket = socket;
        }

        public void run() {
            try (PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(),"UTF-8"), true);
                 BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                 ObjectOutputStream objectOutputStream=new ObjectOutputStream(clientSocket.getOutputStream())) {

                String inputLine;
                while ((inputLine = in.readLine()) != null) {
                    System.out.println("received " + inputLine);
                    Client client=new Client(inputLine,clientSocket);
                    Squad squad=new Squad(client);
                    Client test1=new Client("test1",clientSocket);
                    Squad stest1=new Squad(test1);
                    Client test2=new Client("test2",clientSocket);
                    Squad stest2=new Squad(test2);
                    stest1.clients.add(client);
                    stest1.clients.add(test2);
                    squad.clients.add(test1);
                    squad.clients.add(test2);
                    String connected="1";
                    out.println(connected);
                    System.out.println("connected: "+connected);
                    send_list_of_squads(objectOutputStream);
                    String request=receive_message(clientSocket);
                    String[] array=request.split("/");
                    if(array[0].equalsIgnoreCase("11" )){
                        if ( !client.isInSquad()){
                            String Owner=array[1];
                            for(int i=0;i<Squad.Squads.size();i++){
                                if(Squad.Squads.get(i).getOwner().getUserName().equalsIgnoreCase(Owner)){
                                    Client owner=Squad.Squads.get(i).getOwner();
                                    send_message(owner.getSocket(),"11/"+client.getUserName());
                                    String message=receive_message(owner.getSocket());
                                    if(message=="0"){
                                        owner.getSquad().clients.add(client);
                                        send_message(client.getSocket(),"Accepted in the squad");

                                    } else if (message=="1") {
                                        send_message(client.getSocket(),"Your request denied");
                                    }
                                }
                            }
                        }

                    } else if (array[0].equalsIgnoreCase("22")) {
                        new Squad(client);
                        System.out.println("a new squad created for "+client.getUserName());
                        send_message(client.getSocket(),"a new squad created for "+client.getUserName());

                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void send_list_of_squads(ObjectOutputStream oos) throws IOException {
        System.out.println("list of squads sent");

        ArrayList<HashMap<String,Integer>> sendingList= new ArrayList<>();

        System.out.println("squads size in server: "+Squad.Squads.size());
        for(int i=0;i<Squad.Squads.size();i++){
            HashMap<String,Integer> map=new HashMap<>();
            map.put(Squad.Squads.get(i).getOwner().getUserName(),Squad.Squads.get(i).clients.size());
            sendingList.add(map);
        }
        System.out.println("size of sending map in server: "+sendingList.size());
        oos.writeObject(sendingList);
       oos.flush();

    }
    public static String receive_message(Socket socket) throws IOException {
        BufferedReader bf=new BufferedReader(new InputStreamReader(socket.getInputStream()));
        return bf.readLine();
    }
    public static void send_message(Socket socket,String message) throws IOException {
        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
        out.println(message);
    }
}

客户端代码

package org.example;

import javax.swing.*;
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;

public class TCP {
    static Socket socket;
    private String uername="";

    public String getUername() {
        return uername;
    }

    public void setUername(String uername) {
        this.uername = uername;
    }

    public static void main(String[] args) throws IOException {

    }

    public TCP() throws IOException {
        socket=new Socket("localhost",1234);
        this.setUername(JOptionPane.showInputDialog(null,"USERNAME: "));
        System.out.println("after getting username");
        TCP.sendMessage(getUername());
        System.out.println("after sending username");
        BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));

        Client.setClient(new Client(getUername()));

        new Thread(() -> {
            try {
                String response;
                Scanner scanner=new Scanner(socket.getInputStream());
                while ((response =reader.readLine()) != null) {
                    System.out.println( response);
                    System.out.println("result: "+response.equalsIgnoreCase("1"));
                    String[] array = response.split("/");
                    if (response.equalsIgnoreCase("1")) {
                        ArrayList<HashMap<String, Integer>> receiving = TCP.get_list_of_squads(socket);
                        System.out.println("this is size of list of owners: " + receiving.size());

                        String[] squads = new String[receiving.size()];

                        for (int i = 0; i < receiving.size(); i++) {
                            HashMap<String, Integer> map = receiving.get(i);
                            for (String key : map.keySet()) {
                                squads[i] = key + ": " + map.get(key);
                            }
                        }
                        System.out.println("size of squads list item: " + squads.length);
                        JList<String> itemList = new JList<>(squads);
                        itemList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

                        itemList.setBounds(0, 30, 300, 500);
                        SquadFrame.getSquadFrame().add(itemList);

                        itemList.addListSelectionListener(e -> {
                            if (!e.getValueIsAdjusting()) {
                                String chosen_squad = itemList.getSelectedValue();
                                try {
                                    TCP.sendMessage("11/" + getUername() + "/" + chosen_squad);
                                } catch (IOException ex) {
                                    throw new RuntimeException(ex);
                                }

                                JOptionPane.showMessageDialog(null, "request sent to " + chosen_squad);
                            }
                        });
                    } else if (array[0] == "11") {
                        JOptionPane.showMessageDialog(SquadFrame.getSquadFrame(), "Received from server: " + response);
                        int response_of_request = JOptionPane.showConfirmDialog(null, "wants to join to your squad. Would you accept?", "acception", JOptionPane.YES_NO_OPTION);
                        if (response_of_request == JOptionPane.YES_OPTION) {
                            TCP.sendMessage("0");
                        } else if (response_of_request == JOptionPane.NO_OPTION) {
                            TCP.sendMessage("1");
                        } else {
                            System.out.println("client closed the dialog");
                        }
                    }
                    System.out.println("Received from server: " + response);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }).start();
    }

    public static void sendMessage(String message) throws IOException {
        System.out.println("sending message is: "+message);
        PrintWriter printWriter=new PrintWriter(socket.getOutputStream());
        printWriter.println(message);
        printWriter.flush();
    }
    public static String getMessage(){
        String str="";
        InputStreamReader in= null;
        try {
            in = new InputStreamReader(socket.getInputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        BufferedReader bf=new BufferedReader(in);
        try {
            str=bf.readLine();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return str;
    }
    public static ArrayList<HashMap<String,Integer>> get_list_of_squads(Socket socket) throws IOException, ClassNotFoundException {
        System.out.println("getting list of squads");
        ArrayList<HashMap<String,Integer>> receiving=new ArrayList<>();
        System.out.println("before inputsreaem" );
        ObjectInputStream in=new ObjectInputStream(socket.getInputStream());
        System.out.println("afetr inputsreaem" );
        System.out.println("instance : " + (in.readObject() instanceof ArrayList<?>));
        if(in.readObject() instanceof ArrayList<?>){
            System.out.println("in is array List");
            receiving=(ArrayList<HashMap<String, Integer>>) in.readObject();
        }
        System.out.println("size of receiving in tcp: "+receiving.size());
        return receiving;
    }
    public static String[] get_list_of_clients() throws IOException, ClassNotFoundException {
        ObjectInputStream in=new ObjectInputStream(socket.getInputStream());
        String[] clients=(String[]) in.readObject();
        return clients;
    }
    public static void send_requist_for_squad(){
    }
}

问题根源与修复方案

核心问题

  1. 流类型混合冲突:服务器同时用PrintWriter(字符流)和ObjectOutputStream(对象流)操作同一个Socket输出流。ObjectOutputStream初始化时会写入二进制序列化头部,这部分数据被客户端的字符流读取后就变成了乱码��,之后才是正常的'1'。
  2. 客户端读取逻辑混乱:同时用BufferedReader和Scanner读取同一个输入流,且get_list_of_squads里重复调用readObject(),导致数据读取错位。
  3. 字符串比较错误:用==比较字符串(比如message=="0"),应该用equals做内容比较。

修复步骤

服务器端修改

1. 移除对象流,统一用字符流通信

删掉ObjectOutputStream相关代码,把 squad 列表转成字符串格式发送:

public void run() {
    // 只保留字符流,显式指定UTF-8
    try (PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(),"UTF-8"), true);
         BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8"))) {

        String inputLine;
        while ((inputLine = in.readLine()) != null) {
            System.out.println("received " + inputLine);
            Client client=new Client(inputLine,clientSocket);
            // 省略测试代码...
            String connected="1";
            out.println(connected);
            System.out.println("connected: "+connected);
            
            // 用字符流发送squad列表
            sendSquadsAsString(out);
            
            // 复用已有in流,不要重新创建BufferedReader
            String request=in.readLine();
            String[] array=request.split("/");
            // 字符串比较改用equals
            if(array[0].equalsIgnoreCase("11" )){
                if ( !client.isInSquad()){
                    String Owner=array[1];
                    for(int i=0;i<Squad.Squads.size();i++){
                        if(Squad.Squads.get(i).getOwner().getUserName().equalsIgnoreCase(Owner)){
                            Client owner=Squad.Squads.get(i).getOwner();
                            send_message(out, "11/"+client.getUserName());
                            String message=in.readLine();
                            if("0".equals(message)){
                                owner.getSquad().clients.add(client);
                                send_message(out, "Accepted in the squad");
                            } else if ("1".equals(message)) {
                                send_message(out, "Your request denied");
                            }
                        }
                    }
                }
            } 
            // 省略其他逻辑...
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            clientSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// 新增:把squad列表转成逗号分隔的字符串
private static void sendSquadsAsString(PrintWriter out) {
    StringBuilder sb = new StringBuilder();
    for(int i=0;i<Squad.Squads.size();i++){
        Squad squad = Squad.Squads.get(i);
        sb.append(squad.getOwner().getUserName()).append(":").append(squad.clients.size());
        if(i != Squad.Squads.size()-1){
            sb.append(",");
        }
    }
    out.println(sb.toString());
}

// 修改send_message,复用已有的PrintWriter
public static void send_message(PrintWriter out, String message) {
    out.println(message);
}

客户端修改

1. 统一用BufferedReader读取,移除Scanner

2. 解析服务器发送的字符串格式squad列表

public TCP() throws IOException {
    socket=new Socket("localhost",1234);
    this.setUername(JOptionPane.showInputDialog(null,"USERNAME: "));
    System.out.println("after getting username");
    TCP.sendMessage(getUername());
    System.out.println("after sending username");
    BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));

    Client.setClient(new Client(getUername()));

    new Thread(() -> {
        try {
            String response;
            // 移除多余的Scanner
            while ((response =reader.readLine()) != null) {
                System.out.println( response);
                System.out.println("result: "+response.equalsIgnoreCase("1"));
                if (response.equalsIgnoreCase("1")) {
                    // 读取字符串格式的squad列表
                    String squadStr = reader.readLine();
                    ArrayList<HashMap<String, Integer>> receiving = parseSquadString(squadStr);
                    System.out.println("this is size of list of owners: " + receiving.size());
                    // 省略UI逻辑...
                } 
                // 用startsWith判断,避免字符串引用问题
                else if (response.startsWith("11/")) {
                    String[] array = response.split("/");
                    JOptionPane.showMessageDialog(SquadFrame.getSquadFrame(), "Received from server: " + response);
                    int response_of_request = JOptionPane.showConfirmDialog(null, array[1] + " wants to join your squad. Accept?", "Request", JOptionPane.YES_NO_OPTION);
                    if (response_of_request == JOptionPane.YES_OPTION) {
                        TCP.sendMessage("0");
                    } else if (response_of_request == JOptionPane.NO_OPTION) {
                        TCP.sendMessage("1");
                    } else {
                        System.out.println("client closed the dialog");
                    }
                }
                System.out.println("Received from server: " + response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }).start();
}

// 新增:解析服务器发送的squad字符串
private static ArrayList<HashMap<String, Integer>> parseSquadString(String squadStr) {
    ArrayList<HashMap<String, Integer>> receiving = new ArrayList<>();
    if(squadStr == null || squadStr.isEmpty()){
        return receiving;
    }
    String[] squads = squadStr.split(",");
    for(String s : squads){
        String[] parts = s.split(":");
        HashMap<String, Integer> map = new HashMap<>();
        map.put(parts[0], Integer.parseInt(parts[1]));
        receiving.add(map);
    }
    return receiving;
}

// 修改sendMessage,显式指定UTF-8并开启自动flush
public static void sendMessage(String message) throws IOException {
    System.out.println("sending message is: "+message);
    PrintWriter printWriter=new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);
    printWriter.println(message);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 23:19:54