【问题标题】:Java Client-Server Programming: Shared Memory Between ClientsJava 客户端-服务器编程:客户端之间的共享内存
【发布时间】:2026-01-08 07:55:01
【问题描述】:

我正在使用 Java 开发一个简单的 2D 多人游戏,遵循客户端-服务器模型。套接字编程方面的功能很简单:

  • 客户端向服务器发送他们的字符数据(x 位置、y 位置、健康点等)
  • 服务器将更新的字符数据注册到一个存储所有不同客户端字符数据的表中
  • 服务器将表格发回给客户端,以便他们可以渲染其他字符

我遇到了一个奇怪的问题,我想帮助理解,以便我可以推进项目。这是我现在正在运行的代码。

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Set;
import java.util.Vector;
import java.util.HashSet;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server
{

    private static Vector<Integer> IDs = new Vector<>();

    public static void main(String[] args) throws Exception
    {
        ExecutorService pool = Executors.newFixedThreadPool(32);

        try (ServerSocket listener = new ServerSocket(40000)) 
        {
            System.out.println("The server is up.");
            while (true)
            {
                pool.execute(new Player(listener.accept()));
            }
        }
    }

    private static class Player implements Runnable
    {
        private Socket socket;
        private Scanner input;
        private PrintWriter output;
        private int ID;

        public Player(Socket socket)
        {
            this.socket = socket;
            this.ID = IDs.size() + 1;
            IDs.add(ID);
        }

        public void run()
        {
            try
            {
                input = new Scanner(socket.getInputStream());
                output = new PrintWriter(socket.getOutputStream(), true);

                while(input.hasNextLine())
                {
                    String result = "";
                    for(int i = 0; i < IDs.size(); i++)
                    {
                        result += (IDs.get(i) + " ");
                    }
                    output.println(result);
                }
            }
            catch(Exception e)
            {
                System.out.println(e);
            }
        }
    }
}
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        try (Socket socket = new Socket("127.0.0.1", 40000)) {
            Scanner scanner = new Scanner(System.in);
            Scanner in = new Scanner(socket.getInputStream());
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            while (scanner.hasNextLine()) {
                out.println(scanner.nextLine());
                System.out.println(in.nextLine());
            }
            in.close();
            scanner.close();
        }
    }
}

我想要发生的是:每次客户端向服务器发送任何消息时,服务器都会用一个 ID 列表进行响应(每个连接的客户端都会获得一个新的 ID)。

实际发生了什么:

连接的第二个客户端能够看到已经连接的第一个客户端。但是第一个客户端无法看到有第二个客户端连接。

感谢您的帮助。

【问题讨论】:

  • 您永远不会使用来自客户端的任何输入。
  • 什么意思?我不清楚你所说的“消费”是什么意思,因此不清楚它为什么重要。
  • @vrealwavy 刚刚添加了解释 user207421 含义的答案。

标签: java multithreading sockets client-server


【解决方案1】:

服务器循环

while(input.hasNextLine())
{
    String result = "";
    for(int i = 0; i < IDs.size(); i++)
    {
        result += (IDs.get(i) + " ");
    }
    output.println(result);
}

从不调用input.nextLine(),这意味着input.hasNextLine() 始终为真,因此服务器用输出淹没套接字,直到缓冲区已满。

这可以通过启动客户端,终止服务器,然后继续按 Enter 来查看。即使服务器不在,客户端也会继续接收数据,直到缓冲区被清空。

在循环中添加以下行:

System.out.println(this.ID + ": " + input.nextLine());

这将使服务器按照预期使用来自客户端的线路,并允许您查看/验证数据流动。

【讨论】:

  • 传奇。太感谢了。你能推荐一个很好的资源来学习这些东西吗?
  • 学习如果不从流中读取,就不会消耗数据的好资源?抱歉,不,我不知道有什么资源专门教这个。
最近更新 更多