0

嘿那里堆栈溢出。

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

这显然是一个糟糕的聊天程序,所以我实现了一个处理程序数组列表,目的是将一个客户端写入的内容发送给所有客户端。问题是我无法让它工作,现在我在客户端和服务器之间输入了 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.");
    }

}
}
4

1 回答 1

2

这是给你的一个错误:

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

第一次通过外循环时,您将通过内循环。第二通过外循环,handlerIterator已经用尽,所以它会返回falsehasNext()你永远不会再进入内循环。

相反,使用 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 向服务器发送“世界”
  5. ClientB 从其缓冲区中读取“hello”
  6. 服务器向两个客户端流打印“世界”

所以现在两个客户端都看到了 ClientA 的消息,但没有看到 ClientB 的消息。你会不断得到这种奇怪的延迟效果,最终缓冲区会填满并阻塞。

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

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

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

于 2013-04-03T04:40:39.523 回答