【问题标题】:How to send data from Server to multiple Clients using Sockets?如何使用套接字将数据从服务器发送到多个客户端?
【发布时间】:2015-10-25 12:27:38
【问题描述】:

我有简单的服务器-客户端程序:

public class Server extends Thread {
    private ServerSocket server;

    public Server(int port) {
        try {
            this.server = new ServerSocket(port);
            System.out.println("New server initialized!");
            this.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void run() {
        while (true) {
            try {
                Socket client = server.accept();
                System.out.println(client.getInetAddress().getHostName()
                        + " connected");
                new ServerHandler(client);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

服务器处理程序必须在流中发送消息:

public class ServerHandler extends Thread {
    protected Socket client;
    protected String userInput;
    protected PrintWriter out;
    protected BufferedReader console;

    public ServerHandler(Socket client) {
        this.client = client;
        this.userInput = null;
        this.start();
    }

    public void run() {
        System.out.println("New Communication Thread Started");
        System.out.println("Enter message:");
        try {
            this.out = new PrintWriter(client.getOutputStream(), true);
            this.console = new BufferedReader(new InputStreamReader(System.in));
            while ((this.userInput = console.readLine()) != null) {
                this.out.println(userInput);
            }               
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

客户端收到该消息:

public class Client {
    protected Socket client;
    protected BufferedReader in;

    public Client(String hostName, int ip) {
        try {
            this.client = new Socket(hostName, ip);
            this.in = new BufferedReader(new InputStreamReader(
                    this.client.getInputStream()));
            String buffer = null;
            while ((buffer = in.readLine()) != null) {
                System.out.println(buffer);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

它适用于一个客户端,但是当我启动新客户端时,会出现从服务器接收消息的问题。 我做错了什么?

【问题讨论】:

  • 不确定这是否与您的问题有关,但是在您的 Server 类中,您创建了一个新的 ServerHandler 实例,但您没有将其分配给任何东西。没有任何引用它,它可以随时被垃圾收集。
  • 您的服务器中需要一个套接字连接的arraylist。将每个客户端放在一个线程上,然后在您的服务器中创建一个线程,将数据发送到您的客户端。确保你在你的数组列表中synchronize
  • @JohnSheridan 这不正确。它扩展了 Thread,并且它的构造函数调用 start(),所以在它退出之前它是不适合 GC 的。
  • @EJP 你说得对。一定是梦游。忘记了正在运行的线程被视为 GC 根并且不受 GC 影响。感谢您选择这个。
  • 更改了我的代码但仍有问题。请阅读下面的答案。

标签: java multithreading sockets client server


【解决方案1】:

我找到了答案:

public class Server extends Thread {
    private ServerSocket server;
    protected List<ClientHandler> clients;

    public Server(int port) {
        try {
            this.server = new ServerSocket(port);
            System.out.println("New server initialized!");
            clients = Collections
                    .synchronizedList(new ArrayList<ClientHandler>());
            this.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void run() {
        while (true) {
            try {
                Socket client = server.accept();
                System.out.println(client.getInetAddress().getHostName()
                        + " connected");
                ClientHandler newClient = new ClientHandler(client);
                clients.add(newClient);
                new SendMessage(clients);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

ClientHandler 代替 Serverhandler 类:

public class ClientHandler {
    protected Socket client;
    protected PrintWriter out;

    public ClientHandler(Socket client) {
        this.client = client;
        try {
            this.out = new PrintWriter(client.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

线程可以添加到客户端类,但没有它也可以正常工作。我假设是因为当 main 方法调用时自动创建了新线程:

public class Client {
    protected Socket client;
    protected BufferedReader in;

    public Client(String hostName, int ip) {
        try {
            this.client = new Socket(hostName, ip);
            this.in = new BufferedReader(new InputStreamReader(
                    this.client.getInputStream()));
            String buffer = null;
            while ((buffer = in.readLine()) != null) {
                System.out.println(buffer);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }       
}

向客户端发送数据的类:

 public class SendMessage extends Thread {
        protected List<ClientHandler> clients;
        protected String userInput;
        protected BufferedReader console;

        public SendMessage(List<ClientHandler> clients) {
            this.clients = clients;
            this.userInput = null;
            this.start();
        }

        public void run() {
            System.out.println("New Communication Thread Started");
            if (clients.size() == 1) {
                System.out.println("Enter message:");
            }
            try {
                if (clients.size() > 0) {
                    this.console = new BufferedReader(new InputStreamReader(
                            System.in));
                    while ((this.userInput = console.readLine()) != null) {
                        if (userInput != null & userInput.length() > 0) {
                            for (ClientHandler client : clients) {
                                client.out.println(userInput);
                                client.out.flush();
                            Thread.currentThread();
                            Thread.sleep(1 * 1000);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

现在可以了! 刷新数据后需要让 SendMessage 线程休眠。 主服务器启动器:

public static void main(String[] args) {
new Server(1200);
}

客户端启动器的主要内容:

public static void main(String[] args) {
new Client("127.233.0.1", 1200);
}

【讨论】:

  • 如果有人需要工作版本,我可以提供 bitbucket 链接
  • 很久以前做的。这是链接
猜你喜欢
  • 2020-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多