Java 一台服务器多个客户端

Java 一台服务器多个客户端,java,multithreading,tcp,Java,Multithreading,Tcp,我正在处理以下问题: 我需要写一个服务器程序,将接受多个客户端 所有客户端都从服务器订阅相同的数据,例如股票价格更新 每个客户端都可以向服务器发送简单的命令,如“登录”、“停止” 这是我的解决方案,因为我在多线程/tcp方面不是很有经验,我想知道这是一个好的解决方案吗?如果没有,有没有更好的解决办法?每个客户端套接字都需要一个线程吗?谢谢 顺便说一句:很抱歉把每个人都弄糊涂了,这是一个只涉及5-10门课的小项目 class AcceptThread { ...... public

我正在处理以下问题:

  • 我需要写一个服务器程序,将接受多个客户端
  • 所有客户端都从服务器订阅相同的数据,例如股票价格更新
  • 每个客户端都可以向服务器发送简单的命令,如“登录”、“停止”
  • 这是我的解决方案,因为我在多线程/tcp方面不是很有经验,我想知道这是一个好的解决方案吗?如果没有,有没有更好的解决办法?每个客户端套接字都需要一个线程吗?谢谢 顺便说一句:很抱歉把每个人都弄糊涂了,这是一个只涉及5-10门课的小项目

    class AcceptThread {
        ......
        public void run () {
            ControlThread controlThread = new ControlThread();
            controlThread.start();
    
            Socket socket = new Socket(port);
            while (!stop) {
                Socket s = socket.accept();
                controlThread.addClient (s);
            }
        }
    }
    
    class ControlThread {
        Set<Scoket> clients;
        SendDataThread sendDataThread;  
    
        public ControlThread () {
            sendDataThread = new SendDataThread();
            sendDataThread.start();     
        }
    
        public void addClient (Socket socket) {
            clients.add(socket);
            sendDataThread.addListener(socket);
        }
    
        public void run () {
            ......
            for (Socket s : clients) {
                if (s.getInputStream().available()) {
                    //read command from s
                }
            }
            ......              
        }
    }
    
    class SendDataThread () {
        Set<Scoket> listeners;
    
        public void addListener (Socket s) {
            listeners.add(s);
        }
    
        public void run () {
            for (Socket s: listeners) {
                // send data to each listener
            }
        }
    }
    
    类接受线程{
    ......
    公开作废运行(){
    ControlThread ControlThread=新的ControlThread();
    controlThread.start();
    插座=新插座(端口);
    当(!停止){
    sockets=Socket.accept();
    controlThread.addClient;
    }
    }
    }
    类控制线程{
    设置客户;
    SendDataThread SendDataThread;
    公共控制线程(){
    sendDataThread=新的sendDataThread();
    sendDataThread.start();
    }
    公共void addClient(套接字){
    clients.add(socket);
    sendDataThread.addListener(套接字);
    }
    公开作废运行(){
    ......
    用于(套接字s:客户端){
    如果(s.getInputStream().available()){
    //从s读取命令
    }
    }
    ......              
    }
    }
    类SendDataThread(){
    设置听众;
    公共void addListener(套接字){
    侦听器。添加(s);
    }
    公开作废运行(){
    用于(套接字s:侦听器){
    //向每个侦听器发送数据
    }
    }
    }
    
    每个客户端套接字都需要一个线程吗?

    不,事实上,我甚至不推荐它。如果这是一个小项目,并且您不想使用任何现有库,我建议您使用和。使用所谓的选择器,您可以轻松地以非阻塞方式监视客户端的传入数据

    以下是一些有用的链接:


    使用标准技术解决这个问题怎么样

    JMS主题 用于发布已传递消息的分发机制 多个订阅者

    谢谢顺便说一句:很抱歉把每个人都弄糊涂了,这是一个只涉及5-10门课的小项目

    class AcceptThread {
        ......
        public void run () {
            ControlThread controlThread = new ControlThread();
            controlThread.start();
    
            Socket socket = new Socket(port);
            while (!stop) {
                Socket s = socket.accept();
                controlThread.addClient (s);
            }
        }
    }
    
    class ControlThread {
        Set<Scoket> clients;
        SendDataThread sendDataThread;  
    
        public ControlThread () {
            sendDataThread = new SendDataThread();
            sendDataThread.start();     
        }
    
        public void addClient (Socket socket) {
            clients.add(socket);
            sendDataThread.addListener(socket);
        }
    
        public void run () {
            ......
            for (Socket s : clients) {
                if (s.getInputStream().available()) {
                    //read command from s
                }
            }
            ......              
        }
    }
    
    class SendDataThread () {
        Set<Scoket> listeners;
    
        public void addListener (Socket s) {
            listeners.add(s);
        }
    
        public void run () {
            for (Socket s: listeners) {
                // send data to each listener
            }
        }
    }
    
    这肯定没什么问题。所有更高级别的抽象都以某种方式基于套接字。除非您的项目足够大,否则不需要拉一系列其他框架/工具包来执行相同的工作。线程很便宜(甚至可以从多核体系结构中获益),尽管使用@aioobe建议的
    SelectableChannels
    也不是一个坏主意

    当您的项目需要时,您可以随时了解其他进程间通信方法(消息传递、远程方法invocaton等,以及大约100种实现)


    但是,您可能希望限制服务器同时使用的线程数。这可以很容易地通过声明一个大小等于您想要服务的线程数的信号量来实现。另一个有趣的事情是使用java更好地重用资源。p> 其他人提到可以使用nio库来减少必要的线程数量。我只是想指出,您当前的示例代码将无法工作。使用标准io流时,必须为每个套接字使用线程。
    available()
    方法(通常)几乎没有用处,并且不会阻止您的控制线程阻塞。

    除非这是作业,你应该看看现有的解决方案,而不是从SabsCuSoT开始,不要有一个接受的方法…我认为JMS系统有点沉重,而且没有真正的回报除非大规模使用。此外,您可能最终会使用轻量级较小的应用服务器来支持它(例如,jboss而不是tomcat/jetty)。但是,在正确的项目中使用良好且有用的技术。你是对的,我正在谈论的项目是一个小项目,你认为我的解决方案对一个小项目来说是一个好的解决方案吗?当然,对我来说,编程socketes的效率是一半,但乐趣是两倍。有很多很好的高级辅助工具,但是自己编写套接字编程并没有什么根本性的错误。Bence,你也很有帮助。我相信有一天,当我有更大的项目要开发时,我会使用JMS。这个答案很好。我只是不同意一点:每个客户机一个线程的方法不容易适应线程池,因为每个客户机一个线程的整体思想是它允许您使用阻塞io。如果你使用阻塞io,线程池对你没有多大好处。ROX NIO教程是垃圾。盖伊甚至不知道关闭频道会取消钥匙,他还发明了很多其他事情上不存在的困难。