用于多用户聊天程序的ArrayList

时间:2013-04-03 00:45:46

标签: java

嘿堆栈溢出。

所以我一直在做一个聊天程序来教自己一些Java,我把它运行到任意数量的客户端可以自由连接到服务器的程度,但每个客户端只能与服务器通信。

这显然是一个糟糕的聊天程序,所以我实现了一个处理程序的arrayList,目的是发送一个客户端写入所有客户端的内容。问题是我无法正常工作,现在我的程序在客户端和服务器之间输入3行文本后崩溃。

请查看我的代码。我将重点介绍在尝试实现数组列表时我更改的代码部分。我想我只是把事情搞错了。

服务器代码:

    import java.io.*;
    import java.net.*;
    import java.util.*;;

    public class Server{
    //----------------------------------------------------
    ArrayList<Handler> handlers = new ArrayList<Handler>();
    //----------------------------------------------------
public static void main(String[] args){

    try{
        ServerSocket ss = new ServerSocket(8822);
        while(true){

            Socket s = ss.accept();
            new Handler(s).start();



        }
    }catch(Exception e){
        System.out.println(e.getMessage());
    }
}
    }

    class Handler extends Thread{

Socket socket;
boolean notdone;
BufferedReader br;
PrintWriter pw;
String line;


public Handler(Socket socket){
    this.socket = socket;
    notdone = true;
}

public void run(){

    //------------------
    handlers.add(this);
    //------------------

    try{
        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);
                    //--------------------------------------------------------
        Iterator<Handler> handlerIterator = handlers.iterator();
                    //--------------------------------------------------------
        while(notdone){

            line = br.readLine();

            if(line.equals("bye")){
                System.out.println("Client said 'bye'");
                notdone = false;
                break;
            }else{
                System.out.println("Echo: " + line);
                            //----------------------------------------------
                while (handlerIterator.hasNext()){
                    Handler current = handlerIterator.next();

                    current.pw.println(line);

                }
                            //----------------------------------------------
            }

        }
        br.close();
        pw.close();
        socket.close();

    }catch(Exception e){
        System.out.println(e);
        System.out.println("Client severed connection.");
    }
}
    }

至于客户,我想我应该在突出显示的部分更改一些内容, 但我不确定是什么。

客户代码:

import java.io.*;
import java.net.*;
import java.util.*;

public class Client{

public static void main(String[] args){


    try{
        Socket s = new Socket("localhost", 8822);

        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()),true);

        Scanner scan = new Scanner(System.in);
        boolean notdone = true;

        while(notdone){
            String outString = scan.nextLine();
            if(outString.equals("bye")){
                pw.println(outString);
                notdone = false;
            }else{
                            //------------------
                pw.println(outString);
                String inString = br.readLine();
                            //------------------

                System.out.println("Received: " + inString);
            }
        }
        br.close();
        pw.close();
        s.close();

    }catch(Exception e){
        System.out.println("Server severed connection.");
    }

}
}

1 个答案:

答案 0 :(得分:2)

这是你的一个错误:

    Iterator<Handler> handlerIterator = handlers.iterator();
    while(notdone){
        // ...
        while (handlerIterator.hasNext()){
            Handler current = handlerIterator.next();
            // ....
        }
    }

第一次通过外循环时,您将通过内循环。通过外部循环的{em>秒时间handlerIterator已经用尽,因此它将为false返回hasNext(),您将永远不再进入内循环

相反,使用for-each循环:

    while(notdone){
        // ...
        for (Handler current : handlers){
            // ....
        }
    }

这相当于(但更简洁)

    while(notdone){
        // ...
        Iterator<Handler> handlerIterator = handlers.iterator()
        while (handlerIterator.hasNext()){
            Handler current = handlerIterator.next();
            // ....
        }
    }

同时,在客户端,

            pw.println(outString);
            String inString = br.readLine();

表示您只从服务器读取并且始终在写入服务器之后。所以客户不能只听。这对单个客户端来说应该没问题,但是如果你有两个客户端,那么你会得到这个:

  1. ClientA向服务器发送“hello”
  2. 服务器向两个客户端流打印“hello”
  3. ClientA从其缓冲区读取“hello”(ClientB没有读取任何内容)
  4. ClientB将“world”发送到Server
  5. ClientB从其缓冲区中读取“hello”
  6. 服务器向两个客户端流打印“world”
  7. 所以现在两个客户都看到了ClientA的消息,但没有看到ClientB的消息。你将继续获得这种奇怪的延迟效果,最终缓冲区将被填满并阻塞。

    真正的解决方案是每个客户端都需要一个单独的线程来进行读写。但这在代码难度上是一个相当大的跳跃。我想你应该看看BufferedReader#ready(),它告诉你是否有数据等待阅读。在客户端,您可以在while-not-done循环的开头使用它:

    while(br.ready()) {
        String inString = br.readLine();
        // ...
    }
    // Now all the messages from the server have been printed
    

    你仍然会遇到客户需要不断交谈的问题,但只要他们这样做,事情就应该有效。