Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 多线程服务器转换为SSL后,回显消息时出现问题_Java_Multithreading_Ssl - Fatal编程技术网

Java 多线程服务器转换为SSL后,回显消息时出现问题

Java 多线程服务器转换为SSL后,回显消息时出现问题,java,multithreading,ssl,Java,Multithreading,Ssl,我有一个多线程聊天服务器,我已将其转换为使用JavaSSL套接字 此原始模型(不带SSL)使用客户端控制的“ServerThreads”与其他客户端通信,方法是将消息发送到服务器端的“ClientThreads”,然后将其消息回显到所有其他ServerThreads 下面是ServerThread\u w\u SSL(客户端)的运行方法 以下是ClientThread\u w\u SSL(服务器端)的运行方法 原始程序使用常规套接字,但在转换为SSL套接字后,我遇到了一个问题:输入没有从Clie

我有一个多线程聊天服务器,我已将其转换为使用JavaSSL套接字

此原始模型(不带SSL)使用客户端控制的“ServerThreads”与其他客户端通信,方法是将消息发送到服务器端的“ClientThreads”,然后将其消息回显到所有其他ServerThreads

下面是ServerThread\u w\u SSL(客户端)的运行方法

以下是ClientThread\u w\u SSL(服务器端)的运行方法

原始程序使用常规套接字,但在转换为SSL套接字后,我遇到了一个问题:输入没有从ClientThreads(服务器端)回显到ServerThreads(客户端)

在我第一次尝试转换为SSL时,我使用了证书、密钥库和信任库。我遇到了与这里没有它们时相同的问题,而是只使用默认套接字工厂,它依赖于JDK附带的cacerts文件

请注意,在遇到此错误之前,要解决的第一个问题是客户端和服务器之间发生的握手失败,握手在第一次调用PrintWriter.flush()时启动,这在客户端向服务器发送聊天消息时立即发生。只有在ClientThread(服务器)和ServerThread(客户端)中手动启用受支持的密码套件,然后至少在ClientThread(如果不是两者)中调用SSLSocket.StartHandshake()才能解决此问题

现在,服务器正在接收来自客户端的消息,但它没有将消息回显到客户端

当我在调试器中运行它并尝试单步执行代码时,我发现ClientThread接收客户机的消息,并通过对每个ClientThread的PrintWriter调用write()将其发送回,然后flush()。ServerThread应该通过调用InputStream.available()来接收它,以检查输入而不阻塞,但available()始终返回“0字节”,因此它不会命中Scanner.nextLine()

因此,Printwriter.write()和.flush()都没有发送数据,或者InputStream.available()没有读取数据

编辑:经过更多的调试和测试,我只能将问题缩小到服务器端的输出。我通过让服务器在等待接收消息之前立即发送自己的消息来确定这一点,并让客户端只获取nextLine(),而不是首先使用available()检查。由于此测试失败,它显示数据必须被阻止,以某种方式仅来自服务器端


编辑2:我将代码更改为使用ObjectInputStreams和ObjectOutStreams,而不是使用扫描仪和PrintWriter。现在,我从一个可序列化的类中发送“Message”对象,我创建这个类只是为了保存字符串。这修复了来自服务器的消息的输出问题。如果我通过调用readObject()使客户端简单地等待输入,它将从服务器接收消息。但是,如果我首先使用InputStream的availble()方法,即使它不应该返回0,它仍然只返回0。由于InputStream serverInStream是由socket.getInputStream()初始化的,因此它会得到一个带有ssl.InputRecord的ssl.AppInputStream,我猜这两个函数中的一个没有正确实现available()。

我发现了:问题是available(),在Java中使用ssl是没有用的

 @Override
public void run(){
    System.out.println("Welcome :" + userName);

    System.out.println("Local Port :" + socket.getLocalPort());
    System.out.println("Server = " + socket.getRemoteSocketAddress() + ":" + socket.getPort());
    //setup handshake
    socket.setEnabledCipherSuites(socket.getSupportedCipherSuites());

    try{
        PrintWriter serverOut = new PrintWriter(socket.getOutputStream(), false);
        InputStream serverInStream = socket.getInputStream();
        Scanner serverIn = new Scanner(serverInStream);
        // BufferedReader userBr = new BufferedReader(new InputStreamReader(userInStream));
        // Scanner userIn = new Scanner(userInStream);
        socket.startHandshake();

        while(!socket.isClosed()){
            if(serverInStream.available() > 0){
                if(serverIn.hasNextLine()){
                    System.out.println(serverIn.nextLine());
                }
            }
            if(hasMessages){
                String nextSend = "";
                synchronized(messagesToSend){
                    nextSend = messagesToSend.pop();
                    hasMessages = !messagesToSend.isEmpty();
                }
                serverOut.println(userName + " > " + nextSend);
                serverOut.flush();
            }
        } 
@Override
public void run() {
    try{
        // setup
        this.clientOut = new PrintWriter(socket.getOutputStream(), false);
        Scanner in = new Scanner(socket.getInputStream());

        //setup handshake
        socket.setEnabledCipherSuites(socket.getSupportedCipherSuites());
        socket.startHandshake();
        // start communicating
        while(!socket.isClosed()){
            if(in.hasNextLine()){
                String input = in.nextLine();
                // NOTE: if you want to check server can read input, uncomment next line and check server file console.
                 System.out.println(input);
                for(ClientThread_w_SSL thatClient : server.getClients()){
                    PrintWriter thatClientOut = thatClient.getWriter();
                    if(thatClientOut != null){
                        thatClientOut.write(input + "\r\n");
                        thatClientOut.flush();
                    }
                }
            }
        }