【问题标题】:Why socket closing itself after sending data once?为什么套接字在发送一次数据后会自行关闭?
【发布时间】:2021-12-29 22:31:32
【问题描述】:

我有一个客户端-服务器应用程序。 它在客户端打开一个套接字,然后我输入要发送的数据,它也被发送到其他客户端,但随后套接字被关闭。为什么?我尝试了许多不同的方法,例如将dindout 转移到线程本身,添加一些处理程序等。但还没有进展。

我看到了一些其他类似的问题,但那里的解决方案不适用于我的问题(我在套接字方面没有那么经验)。想要解决我的具体问题。

错误:

java.net.SocketException: Socket is closed
    at java.base/java.net.Socket.getInputStream(Socket.java:927)
    at com.uniqueapps.network.ClientThread.lambda$run$1(ClientThread.java:23)
    at java.base/java.lang.Thread.run(Thread.java:833)
java.net.SocketException: Socket is closed
    at java.base/java.net.Socket.getOutputStream(Socket.java:998)
    at com.uniqueapps.network.ClientThread.lambda$run$0(ClientThread.java:28)
    at java.base/java.lang.Thread.run(Thread.java:833)
Exception in thread "Thread-2" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
    at com.uniqueapps.network.ClientThread.lambda$run$0(ClientThread.java:27)
    at java.base/java.lang.Thread.run(Thread.java:833)

Server.java 代码:

package com.uniqueapps.network;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;

public class Server {

    final static int PORT = 5555;
    static ServerSocket serverSocket;
    static ArrayList<ClientThread> clients = new ArrayList<>();
    
    public static void main(String[] args) {
        try {
            serverSocket = new ServerSocket(PORT);
            new Thread(() -> {
                while (true) {
                    try {
                        Socket clientSocket = serverSocket.accept();
                        ClientThread client = new ClientThread(clientSocket);
                        client.run();
                        clients.add(client);
                        System.out.println("New client joined: " + client.socket.getLocalPort());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ClientThread.java 代码:

package com.uniqueapps.network;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;

public class ClientThread implements Runnable {

    Socket socket;

    public ClientThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        new Thread(() -> {
            boolean run = true;
            while (run) {
                try (DataInputStream din = new DataInputStream(socket.getInputStream())) {
                    String text = din.readUTF();
                    if (!text.equals("")) {
                        new Thread(() -> {
                            for (ClientThread clientThread : Server.clients) {
                                try (DataOutputStream dout = new DataOutputStream(clientThread.socket.getOutputStream())) {
                                    dout.writeUTF(text);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }).start();
                    }
                } catch (EOFException ignored) {
                } catch (SocketException e) {
                    e.printStackTrace();
                    Server.clients.remove(this);
                    run = false;
                    System.out.println("Client left: " + socket.getLocalPort());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

Client.java 代码:

package com.uniqueapps.network;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;

public class Client {

    public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost", 5555);
            socket.setKeepAlive(true);

            new Thread(() -> {
                try {
                    DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
                    Scanner scn = new Scanner(System.in);
                    while (true) {
                        String text = scn.nextLine();
                        if (!text.equals("")) {
                            try {
                                dout.writeUTF(text);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            new Thread(() -> {
                try {
                    DataInputStream din = new DataInputStream(socket.getInputStream());
                    while (true) {
                        try {
                            String text = din.readUTF();
                            if (!text.equals("")) {
                                System.out.println(text);
                            }
                        } catch (EOFException ignored) {
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

编辑:

感谢 Michael Lee,我理解了我数周来一直试图理解的问题。我重新编写了代码,但我卡在了一个地方。

我知道“runnable”的.run(); 方法会暂停当前线程,但“thread”的.start(); 不会。所以我从所有地方删除了线程,除了一个。这个地方仍然出现“套接字关闭”错误(如果我在这里保持可运行,那么线程会停止,并且消息不会中继到其他客户端)。我该如何克服呢?

Server.java:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;

public class Server {

    final static int PORT = 8686;
    static ServerSocket serverSocket;
    static ArrayList<ClientThread> clients = new ArrayList<>();

    public static void main(String[] args) {
        try {
            serverSocket = new ServerSocket(PORT);
            System.out.println("Server ready! Running on port " + PORT);
            while (true) {
                try {
                    Socket clientSocket = serverSocket.accept();
                    System.out.println("New client joined: " + clientSocket.getPort());
                    ClientThread client = new ClientThread(clientSocket);
                    System.out.println("Created thread for client.");
                    clients.add(client);
                    System.out.println("Added client to list.");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ClientThread.java:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;

public class ClientThread extends Thread {

    Socket socket;

    public ClientThread(Socket socket) {
        this.socket = socket;
        this.start();
        System.out.println("Started thread for client.");
    }

    @Override
    public void run() {
        try {
            boolean run = true;
            DataInputStream din = new DataInputStream(socket.getInputStream());
            while (run) {
                try {
                    String text = din.readUTF();
                    if (!text.equals("")) {
                        for (ClientThread clientThread : Server.clients) {
                            try (DataOutputStream dout = new DataOutputStream(clientThread.socket.getOutputStream())) {
                                dout.writeUTF(text);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } catch (EOFException ignored) {
                } catch (SocketException e) {
                    e.printStackTrace();
                    Server.clients.remove(this);
                    run = false;
                    System.out.println("Client left: " + socket.getPort());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Client.java:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;

public class ClientThread extends Thread {

    Socket socket;

    public ClientThread(Socket socket) {
        this.socket = socket;
        this.start();
        System.out.println("Started thread for client.");
    }

    @Override
    public void run() {
        try {
            boolean run = true;
            DataInputStream din = new DataInputStream(socket.getInputStream());
            while (run) {
                try {
                    String text = din.readUTF();
                    if (!text.equals("")) {
                        for (ClientThread clientThread : Server.clients) {
                            try (DataOutputStream dout = new DataOutputStream(clientThread.socket.getOutputStream())) {
                                dout.writeUTF(text);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } catch (EOFException ignored) {
                } catch (SocketException e) {
                    e.printStackTrace();
                    Server.clients.remove(this);
                    run = false;
                    System.out.println("Client left: " + socket.getPort());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

【问题讨论】:

  • I think the port 5555 is not for personal use.,试试别的,比如 8686。
  • 更改了端口,还是同样的错误@Xarencia
  • 因为您使用单独的线程进行读取和写入,并且在完成后关闭任一线程中的输入/输出流,所以套接字关闭时不是确定性的。从套接字关闭输入流或输出流将关闭整个套接字,包括您没有明确关闭的输出流或输入流。

标签: java sockets socketexception


【解决方案1】:

在您的ClientThread中,在din.readUTF(); if (!text.equals("")) { ...之后,您应该直接开始处理当前线程中的传入数据,而不是初始化一个新线程来处理它们。 p>

因为在您当前的线程中,持有已连接套接字的线程可能之前关闭,新线程甚至还没有启动。正如Java Docs 所说:

void close() 抛出异常

关闭此资源,放弃所有底层资源。此方法在由 try-with-resources 语句管理的对象上自动调用

这就是你得到Socket Closed异常的原因。

还有一点,ServerClient 中的线程太多。大多数时候这样的事情是不必要的,比如说,对于一个相当简单的应用程序。因为它们在您的代码中没有得到很好的管理,这更有可能使您的程序在未来出现意外行为。尝试仅在必要时使用线程,而不是尽可能地使用线程

【讨论】:

  • 感谢您指出问题。我已经考虑了好几个星期了。请查看更新后的问题。
  • 请查看
猜你喜欢
  • 2016-10-08
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多