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(){ } }
问题根源与修复方案
核心问题
- 流类型混合冲突:服务器同时用
PrintWriter(字符流)和ObjectOutputStream(对象流)操作同一个Socket输出流。ObjectOutputStream初始化时会写入二进制序列化头部,这部分数据被客户端的字符流读取后就变成了乱码��,之后才是正常的'1'。 - 客户端读取逻辑混乱:同时用
BufferedReader和Scanner读取同一个输入流,且get_list_of_squads里重复调用readObject(),导致数据读取错位。 - 字符串比较错误:用
==比较字符串(比如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
相关产品推荐
相关产品推荐

