我正在尝试制作一个简单的文本编辑器,可以同时在多个终端之间共享。我有一个服务器
等待新用户,当用户进入共享编辑器时,它只是开始等待输入字符。
public class Server {
public static final int PORT = 8080;
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(PORT);
while (true) {
Socket socket = ss.accept();
System.out.println("A new user entered the sever");
new Thread(() -> serve(socket)).start();
}
}
private static void serve(Socket socket) {
try {
while (!socket.isClosed() && !socket.isInputShutdown()) {
System.out.println("hey " + socket.isClosed() + " " + socket.isInputShutdown());
System.out.print(new String(SocketUtil.receiveBytes(socket,1)));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
当用户关闭编辑器时,客户端的套接字将关闭。然而,服务器端的套接字并没有关闭,服务器开始在“等待输入”循环中无限循环。
Client
是一个包含以下方法的单例,在打开和关闭编辑器时调用。
public static void init() {
try {
if (socket == null) socket = new Socket(HOST,Server.PORT);
} catch (IOException e) {
e.printStackTrace();
kill();
throw new Error(e.getMessage());
}
}
public static void kill() {
Check.notNull(socket);
try {
SocketUtil.terminateCommunication(socket);
System.out.println(socket.isClosed());
} catch (IOException e) {
e.printStackTrace();
}
}
最后,这是两个类中使用的实用方法(在 SocketUtil
中):
public static void terminateCommunication(Socket socket) throws IOException {
socket.shutdownInput();
socket.shutdownOutput();
socket.close();
}
public static char[] receiveBytes(Socket socket, int nBytes) throws IOException {
char[] bytes = new char[nBytes];
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
isr.read(bytes);
return bytes;
}
知道为什么在 Client
被杀死后服务器端的套接字没有关闭吗?
最佳答案
Javadoc 中并不太清楚,但是当您显式调用 close()
时,isClosed()
仅返回 true
套接字(请参阅消息来源以确认这一点)。您应该检查异常和 read()
的返回值。如果您在尝试读取(或写入)时读取 -1
或捕获 IOException
,则本质上意味着另一端已关闭连接,因此您也应该关闭您的套接字(最好在 finally
block 中关闭),然后您就完成了该特定连接。您不会在 receiveBytes()
中检查 -1
,但您确实应该检查。如果您想将这两种可能性合并为一种,也许可以抛出一个 EOFException()
,这样堆栈上的代码(在 serve()
中)就不必计算到底发生了什么:
public static char[] receiveBytes(Socket socket, int nBytes) throws IOException {
char[] bytes = new char[nBytes];
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
if (isr.read(bytes) == -1)
throw new EOFException();
return bytes;
}
IOException
规则中的一个异常(exception)(抱歉是双关语)是 SocketTimeoutException
。如果您收到此消息,则连接仍然有效,您也可以重试 read()
。但我相信为了获得这些,您必须在某个地方调用 Socket.setSoTimeout() ,如果没有,那么您可能不应该担心 SocketTimeoutException 。 .
您还应该注意,read()
有时可能会返回部分读取(即小于bytes.length
)。如果 receiveBytes()
准确读取 nBytes
很重要(这可能是,因为您永远不会返回实际读取的字符数),那么您应该在循环中调用它,像这样:
int pos = 0;
while (pos < bytes.length) {
int l;
if ((l = isr.read(bytes, pos, bytes.length - pos)) == -1) {
throw new EOFException();
}
pos += l;
}
我知道这很麻烦,这正是许多开发人员创建像 receiveBytes()
这样的实用方法的原因。
关于java - 为什么我的套接字没有在服务器端关闭?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30014460/