【发布时间】:2021-12-29 22:31:32
【问题描述】:
我有一个客户端-服务器应用程序。
它在客户端打开一个套接字,然后我输入要发送的数据,它也被发送到其他客户端,但随后套接字被关闭。为什么?我尝试了许多不同的方法,例如将din 和dout 转移到线程本身,添加一些处理程序等。但还没有进展。
我看到了一些其他类似的问题,但那里的解决方案不适用于我的问题(我在套接字方面没有那么经验)。想要解决我的具体问题。
错误:
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