觉得慢的原因主要是每个线程会去检查VECTOR中是否有自己的消息 
直观的想法是这些线程接收信息都是被动的 而不应该主动去检查,不没有消息的时候会花费无谓的系统时间。你的想法有点像MEDIATOR PATTERN由一个中间的协调者去处理多个用户间的通信,有可能的做法是做一个共享对象,每个线程都向它发消息,而这个对象则负责转发。

解决方案 »

  1.   

    可以这样子
    public class SocketThread extends Thread implements java.util.Observer
    {
        private java.util.Observable observable = null;
        public SocketThread(java.util.Observable observable)
        {
            this.observable = observable;
        }
        public void run()
        {
            observable.addObserver(this);
            ......
            observable.deleteObserver(this);
        }
        ......
        public void update(Observable observable, Object msg)
        {
         ....发送消息
         }
        接受到信息,则observable.notifyAll(msg);
    }
    而在主线程中
    public class ServerObservable extends java.util.Observable
    {
         public void notifyAll(Object o)
         {
            ....如果信息是发送给某个人的,查找出那个人的Thread,然后调用thread.update(this, o)
            ....如果信息发送给所有人,则
                setChanged();
                notifyObservers(o);
                clearChanged();
         }
    }
      

  2.   

    1.不要用vector,用hashmap之类的hash系的,就算不用hashmap也要考虑使用arraylist2。保存的对象不是消息,而是对应User的各个listener3。考虑建立user1直接到user2的通信连接。比如qq里面通信之前你一定要双击某人头像,这是可以考虑建立两人的通信连接。聊天室里也是要先选和某人密谈。你的原本思路可能不是很正确。这种东西真的要写好需要注意很多细节,good luck
      

  3.   

    服务器端的子线程和主线程可以采用Observer模式,
    对于接受到的消息的处理,可以采用ChainOfResponsibility模式,
    可根据消息的类型分层处理,好处是一旦有新的消息类型加入的话,
    只需增加一条消息处理链而无需对已有的类进行重新组织
      

  4.   

    //: c15:MultiJabberClient.java
    // Client that tests the MultiJabberServer
    // by starting up multiple clients.
    import java.net.*;
    import java.io.*;
    class JabberClientThread extends Thread {
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    private static int counter = 0;
    private int id = counter++;
    private static int threadcount = 0;
    public static int threadCount() {
    return threadcount;
    }
    public JabberClientThread(InetAddress addr) {
    System.out.println("Making client " + id);
    threadcount++;
    try {
    socket =new Socket(addr, 8080);
    } catch(IOException e) {
    System.err.println("Socket failed");
    // If the creation of the socket fails,
    // nothing needs to be cleaned up.
    }
    try {
    in =new BufferedReader(new InputStreamReader(socket.getInputStream()));
    // Enable auto-flush:
    out =new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
    start();
    } catch(IOException e) {
    // The socket should be closed on any
    // failures other than the socket
    // constructor:
    try {
    socket.close();
    } catch(IOException e2) {
    System.err.println("Socket not closed");
    }
    }
    // Otherwise the socket will be closed by
    // the run() method of the thread.
    }
    public void run() {
    try {
    for(int i = 0; i < 25; i++) {
    out.println("Client " + id + ": " + i);
    String str = in.readLine();
    System.out.println(str);
    }
    out.println("END");
    } catch(IOException e) {
    System.err.println("IO Exception");
    } finally {
    // Always close it:
    try {
    socket.close();
    } catch(IOException e) {
    System.err.println("Socket not closed");
    }
    threadcount--; // Ending this thread
    }
    }
    }public class MultiJabberClient {
    static final int MAX_THREADS = 40;
    public static void main(String[] args)throws IOException, InterruptedException {
    InetAddress addr =InetAddress.getByName(null);
    while(true) {
    if(JabberClientThread.threadCount()< MAX_THREADS)
    new JabberClientThread(addr);
    Thread.currentThread().sleep(100);
    }
    }
    } ///:~
      

  5.   

    //: c15:MultiJabberServer.java
    // A server that uses multithreading
    // to handle any number of clients.
    import java.io.*;
    import java.net.*;
    class ServeOneJabber extends Thread {
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    public ServeOneJabber(Socket s) throws IOException {//Socket s这一句是关键,说明socket随着线程的建立而建立
    socket = s;
    in =new BufferedReader(new InputStreamReader(socket.getInputStream()));
    // Enable auto-flush:
    out =new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
    // If any of the above calls throw an
    // exception, the caller is responsible for
    // closing the socket. Otherwise the thread
    // will close it.
    start(); // Calls run()
    }
    public void run() {
    try {
    while (true) {
    String str = in.readLine();
    if (str.equals("END")) break;
    System.out.println("Echoing: " + str);
    out.println(str);
    }
    System.out.println("closing...");
    } catch(IOException e) {
    System.err.println("IO Exception");
    } finally {
    try {
    socket.close();
    } catch(IOException e) {
    System.err.println("Socket not closed");
    }
    }
    }
    }
    public class MultiJabberServer {
    static final int PORT = 8080;
    public static void main(String[] args) throws IOException {
    ServerSocket s = new ServerSocket(PORT);//serversockt只要一个,其他的连接都是用的socket
    System.out.println("Server Started");
    try {
    while(true) {
    // Blocks until a connection occurs:
    Socket socket = s.accept();
    try {
    new ServeOneJabber(socket);
    } catch(IOException e) {
    // If it fails, close the socket,
    // otherwise the thread will close it:
    socket.close();
    }
    }
    } finally {
    s.close();
    }
    }
    } ///:~
      

  6.   

    rosifox(下着鱼的天) :对不起,我不太明白什么叫做Observer模式还有什么ChainOfResponsibility模式,能讲的清楚点吗?
      

  7.   

    但也不至于如此之慢吧,现在我把程序放在一个邮箱[email protected]上,密码是:918918918,希望大家能从程序中看出点眉目,并给我一些建议,谢谢大家了
      

  8.   

    Observer模式也就是观察者模式
    一个对象作为被观察者Subject,
    若干个对象做为观察者Observer,
    Subject发生变化时通知Observer你可以看一下java.util.Observable(Subject)和java.util.Observer的源代码ChainOfResponsibility就是责任链模式,
    一般接口是
    public interface Chain
    {
        void addChain(Chain nextchain);
        void deleteChain(Chain chain);
        void handle(.....);
    }
    可以通过addChain将各个链串连起来,
    如果当前链无法handle,则在handle中可以调用nextchain.handle(...)
    将处理交给下一个链,这样子持续下去直到有一个链能够处理它,则结束链并返回,
    也可以在每个链中处理自己要处理的事情,并交由下一个连处理其它的事情在这个应用中,譬如如果你想写一个日志,
    那么你只要在链中串入一个写日志的链,就可以很方便地实现该功能而无
    需改变原有的类的结构(当然除了将这些链串接在一起的Client程序)
      

  9.   

    这个程序我两年前作过,但是具体的我忘记了,只剩一些思路了.如果你是针对慢的问题,
    在改动不大的前提下(以服务器为中心不建立C2C连接)我建议你可以这样试一下.注意:
    1.其实服务器针对每个用户是两条线程在运行,一条线程管输入另一条管输出,客户端也是如此;
    2.客户端发出的消息中不但需要包括他的内容还需要包括该消息需要发送给何人
    3.不要采用查找公用资源(堆栈,Vector等等),而应该采用入栈,弹栈的方式.思路
    假设a 用户发向 b用户.服务器段有N多对(输入/输出)线程.当a1(输入线程)从睡眠中醒来(怎么醒来?可以睡一定时间或者干脆睡去靠别人唤醒)侦侧到有消息到来时从Socket中得到输入信息时将其加入堆栈(Vector等)中,需要添加消息发向何处的信息.a1再次进入睡眠状态.b2(向b客户端的输出线程)从睡眠中醒来侦测堆栈中的最后入栈的信息是否为发送给b的,如果不是则继续睡眠,如果是则将该信息发送到b客户端并将该信息弹栈,随后b2进入睡眠状态.
    其实关于b2这个地方你可以想想看是否可以使用一个线程来代替所有的发送线程.至少我看过消息中间件有类似的做法.当然这种一直依靠服务器做SWITCH的方式在用户数量众多的情况下效率一定会受到影响.
      

  10.   

    我也推荐一个自己写的吧
    //接受信息线程
    public Receiver extends Thread
    {
       public Receiver(Socket socket, Observable observable)
       {
          ....
       }
       public void run()
       {
          ...阻塞等待接受消息,直到接收到消息
          //可以这样子,将会阻塞直到接受到信息
          //ObjectInputStream ois = new ObjectInputStream(socket.getInputStream);
          //接受到消息后observable.notifyObservers(msg)
       }
    }
    //发送消息类
    public Sender implements Observer
    {
       public Sender(Socket socket)
       {
          ....
       }
       public void update(Observable observable, Object msg)
       {
           //发送msg
       }
    }
    public Server extends Observable
    {
       public Server(MainServer ms)
       {
          ...
       }
       public void server()
       {
           //阻塞等待连接
           //连接之后,创建一个Receiver和一个Sender,调用ms.login(id, sender)
           //封装一个XXID登陆信息
           //调用notifyObservers(msg)
       }
       public void notifyObservers(Object o)
       {
           setChanged();
           ms.handleMessage(this, o);
           clearChanged();
       }
    }
    public MainServer implements Chain
    {
       private HashMap senders;//Map.Entry的key为用户登陆ID,value为一个连接用户的socket构造的Sender
       public void login(String id, Sender sender)
       { 
           //将登陆信息写入senders
       }
       public void handleMessage(Observable observable, Object o)
       {
           //处理该消息(如果是发送给所有,可调用observable.notifyObservers(),否则,可直接从senders中查找到
           //该sender,直接调用,并做相应各种处理
       }
    }
      

  11.   

    我觉得在这个任务当中,服务器的工作并不是一个广播员,他不需要保存到所有的信息。
    服务器的工组更类似一个接线员,他应该做的是把输入的流接到需要的输出流上。
    偶以前做这个东西的时候开发过一个把 InputStream 和 OutputStream 接在一起的类 Pipe,不过性能不佳。
    这样,在服务器端保存的东西应该是一张注册表,上面登记了所有已经登陆的 Client 的标识 和其输入流输出流。
    每当有新的呼叫的时候,Client 唤醒服务器进行接线,然后服务器去睡觉。
      

  12.   

    这个问题我已经解决了,不过还是很感激大伙,我的解决方法是没登录一个用户,就记录下连接的socket和登录的用户名到一个Vector对象里面去,然后为登录的用户产生一个监听线程,在这个线程里面当收到有要转发的消息后,获取该消息中要转发到的用户名,通过此用户名在Vector中找到对应的socket,然后通过此socket把消息发送出去。
    以前我的聊天不能正常进行是我把所有的消息都放到一个消息列表中去,然后由各socket监听线程去找到对应的消息,然后再发送出去,但是socket的消息监听是会堵塞(以前我没有考虑到这一点,我以为socket里面的消息监听过程是一个不停地循环过程)的,这导致后面的消息转发处理过程不能正常进行,现在发现了这一问题,终于把他给解决了。