Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/371.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多线程客户端/服务器-Java.net.SocketException:套接字已关闭_Java_Multithreading_Sockets - Fatal编程技术网

Java多线程客户端/服务器-Java.net.SocketException:套接字已关闭

Java多线程客户端/服务器-Java.net.SocketException:套接字已关闭,java,multithreading,sockets,Java,Multithreading,Sockets,我必须使用Java的socket api编写多线程客户端和服务器。客户端和服务器都是多线程的,因此服务器可以处理多个连接,客户端可以测试服务器处理连接的能力 我的代码在这里: 我有一些问题,可能是相关的。一个,偶尔一个客户端线程会抛出 java.net.SocketException: Socket closed at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStre

我必须使用Java的socket api编写多线程客户端和服务器。客户端和服务器都是多线程的,因此服务器可以处理多个连接,客户端可以测试服务器处理连接的能力

我的代码在这里:

我有一些问题,可能是相关的。一个,偶尔一个客户端线程会抛出

java.net.SocketException: Socket closed
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
    at java.io.InputStreamReader.read(InputStreamReader.java:167)
    at java.io.BufferedReader.fill(BufferedReader.java:136)
    at java.io.BufferedReader.readLine(BufferedReader.java:299)
    at java.io.BufferedReader.readLine(BufferedReader.java:362)
    at ClientThread.run(ClientThread.java:45)
    at java.lang.Thread.run(Thread.java:680)
从它的位置来看,这意味着服务器在客户端完成读取之前正在关闭它的套接字。我怎样才能防止这种情况


此外,即使计算抛出
套接字关闭
异常的线程数,似乎并非所有服务器线程都在发送其输出。例如,30个服务器线程中有23个将发送其输出,但只有22个客户端线程将接收任何内容。通信显然在某处丢失了,我如何防止这种情况

您在ClientThread中的问题是:

private static Socket socket = null;
这意味着所有线程都在为ClientThread的所有实例共享同一个套接字实例。这意味着您的套接字将与会话状态不同步。您的对话是:

客户国:

  • 客户端连接
  • 客户端发送请求
  • 客户端等待响应
  • 客户端收到响应
  • 客户端关闭套接字(应由每个客户端完成)
  • 服务器状态:

  • 服务器等待客户端
  • 服务器读取请求
  • 服务器进程命令
  • 服务器发送响应
  • 服务器关闭套接字
  • 但是,您有30个会话试图同时处于不同的状态,服务器和客户端无法跟踪它们。第一个线程创建套接字发送一个移动到状态2的请求,当它等待时,另一个线程创建另一个套接字,将其写入状态2,当第一个线程唤醒时,它开始讨论线程2创建的新套接字,而线程2尚未完成对它的命令的处理。现在第三个开始并再次覆盖该引用,以此类推。第一个命令永远不会被读取,因为当线程2重写它时,它丢失了对原始套接字的引用,并且它开始读取线程2的命令并将其吐出。一旦线程1到达close语句,它就会关闭套接字,而其他线程正在尝试对其进行读/写,并且抛出异常

    基本上,每个ClientThread都应该创建自己的套接字实例,然后每个会话可以独立于其他正在进行的会话进行。考虑一下,如果您将客户端编写为单线程。然后启动两个单独的进程(运行Java应用程序两次)。每个进程将创建自己的套接字,每个会话将独立工作。您现在拥有的是一个带有30个线程的套接字,通过一个扩音器向服务器发送命令。当每个人都用同一个扩音器大声喊叫时,工作就不能有秩序地进行

    所以总而言之,在ClientThread中从套接字成员中移除静态修饰符,它应该可以很好地开始工作

    就像旁白一样,永远不要将此代码发布到世界上。它有严重的安全问题,因为客户端可以在服务器进程正在运行的安全级别上执行任何命令。因此,任何人都可以相对轻松地拥有您的机器或获取您的帐户。从客户端执行类似命令意味着他们可以发送:

    sudo cat /etc/passwd
    
    例如,捕获您的密码哈希。我认为你只是在学习,但我觉得你应该警惕你正在做的事情,以确保安全

    另一件事是,只有当会话按预期进行时,服务器才会关闭套接字。您真的应该将close()调用移到try块上的finally块中。否则,如果客户端过早地关闭其套接字(这种情况会发生),那么服务器将泄漏套接字,并最终耗尽操作系统中的套接字

    public void run() {
       try {
       } catch( SomeException ex ) {
          logger.error( "Something bad happened", ex );
       } finally {
          out.close();   <<<< not a bad idea to try {} finally {} these statements too.
          in.close();    <<<< not a bad idea to try {} finally {} these statements too.
          socket.close();
       }
    }
    
    public void run(){
    试一试{
    }捕获(某些例外){
    logger.error(“发生了不好的事情”,例如);
    }最后{
    
    out.close();乍一看,我会提出以下问题:(1)您是否在服务器端刷新输出流(以确保没有数据等待写入),(2)在
    ClientThread.java
    的第55-57行,我认为您不需要在关闭套接字的同时关闭流。请尝试不要这样做(在客户端和服务器端)并查看发生了什么。最后(3)查看JavaDoc中的
    close()
    方法,看看这里是否有什么可以说明发生了什么:关于过早关闭。是的,我正在调用flush()每次任何一方发送数据时。但是,您使用最后一个参数将PrintWriter设置为autoflush,因此它已经可以为您执行此操作。不需要flush(),因为在auto flush中设置的PrintWriter将在每次打印*()后调用flush()方法调用。谢谢!这很有道理,我没有把静态修饰符放在那里,所以我对它视而不见。我已经用我的头敲了好几天了。