在客户端 JAVA 中调用 socket.close() 时,套接字未关闭服务器端
Posted
技术标签:
【中文标题】在客户端 JAVA 中调用 socket.close() 时,套接字未关闭服务器端【英文标题】:Socket not closing serverside when calling socket.close() in client JAVA 【发布时间】:2011-03-19 05:35:11 【问题描述】:我在 java 中遇到了套接字问题。我有一个 ServerSocket
正在使用 accept() 进行侦听,并为每个客户端请求生成线程。客户端和服务器之间的通信工作正常。我正在使用输入流从服务器线程中的客户端读取数据,例如:
inputStream = mySocket.getInputStream();
bytes = inputStream.read(buffer);
我的问题是,如果我从客户端调用 socket.close(),bytes = inputStream.read(buffer);
的阻塞调用没有任何反应,它会继续阻塞。但是如果我从服务器关闭套接字,它会起作用,然后客户端的inputStream.read(buffer);
返回“-1”。
服务器主线程:
//SERVER MAIN THREAD, SPAWNS CLIENT THREADS
ServerSocket serverSocket = new ServerSocket(SERVERPORT);
while (listening)
new ServerThread(serverSocket.accept(), monitor).start();
服务器-客户端线程:
public class ServerThread extends Thread
public ServerThread(Socket socket, Monitor monitor)
this.socket = socket;
this.monitor = monitor;
public void run()
byte[] buffer = new byte[1024];
int bytes;
//Listen
while(true)
try
InputStream inputStream = socket.getInputStream();
monitor.doStuffWithOtherThreads(Object myObject);
bytes = inputStream.read(buffer); //Problem
if (bytes == -1)
System.out.println("breaks");
break;
byte[] readBuf = (byte[]) buffer;
String readMessage = new String(readBuf, 0, bytes);
System.out.println(readMessage);
System.out.println(bytes);
catch (IOException e)
System.out.println("Connection closed");
break;
客户:
InetAddress serverAddr = InetAddress.getByName("serverhostname");
socket = new Socket(serverAddr, PORT);
socket.close(); //Close the socket connection from client. Nothing happens in the serverthread
【问题讨论】:
你有一个小例子来展示这种行为吗? inputStream.read(缓冲区);在这种情况下应该返回 -1,你是否明确检查 -1 ? 更新了示例代码。是的,我明确检查 -1。线程仍然阻塞在 read(); 一个简单的解决方案是让客户端在调用close()
之前发送一条“断开连接”消息,然后服务器在收到此消息时退出循环。
是的,我已经考虑过了。但它可能不是最好的解决方案。
您的示例代码不检查 -1。所以要么这仍然是问题,要么不是真正的代码,在这种情况下你仍然需要发布真正的代码。
【参考方案1】:
我不知道我是否理解你的问题,但我想说由服务器关闭套接字是正常的。
在服务器端(在独立线程中),您有监听套接字:
ServerSocket socketServeur = new ServerSocket(port);
然后可能(如果是小型服务器,在同一个线程中)接受传入连接的循环(没有异常管理,可能 socket.close 在 finally 块中):
while (! askedToClose)
Socket socket = socketServeur.accept();
doSomethingWithRequest(socket);
socket.close();
在客户端,您有:
Socket clientSocket = new Socket();
clientSocket.connect(new InetSocketAddress(port));
OutputStream output = clientSocket.getOutputStream();
// send something to server
InputStream input = clientSocket.getInputStream(); // will block until data is available
// reading response
服务器应该知道它何时到达请求的末尾。例如在 http 中它可能是(取自 scala 中的 mockHttpServer,因此可能会有一些错误,但过程是相同的):
void doSomethingWithRequest(Socket socket)
BufferedReader inputReader = new BufferedReader(new InputStreamReader(socket.getInputStream));
StreamWriter outputWriter = new OutputStreamWriter(socket.getOutputStream);
StringBuilder requestBuilder = new StringBuilder();
do
requestBuilder.append(inputReader.read().toChar());
while (!requestBuilder.toString().endsWith("\r\n\r\n"));
saveUri(getUriFromRequest(requestBuilder.toString()));
outputWriter.write("HTTP/1.1 200 OK\r\n\r\n");
outputWriter.flush();
inputReader.close();
outputWriter.close();
编辑: 我阅读了添加的代码,但我仍然不明白:
你调用了 Socket.close(),但是这个方法不是静态的 你在“服务器”中永远循环 我的印象是您为客户端和服务器使用相同的套接字你有 3 个“套接字”:
监听套接字(对象ServerSocket) 接受套接字(socketServer.accept() 发送的对象套接字) 客户端套接字(如上例)服务器打开和关闭侦听和“接受”套接字,应该不会受到客户端套接字管理不良的影响。
如果您希望您的服务器接受多个并发连接,您可以添加一个线程池来接受连接并处理请求和响应。
【讨论】:
我也必须注意,java 不是套接字编程最简单的语言... Ofc Socket 不是静态的?这只是一个例子。它不像我试图在我的客户中那样称呼它。这不像我发布了我的真实代码。我只是试图让自己清楚。唯一的问题是“为什么当套接字靠近客户端时 InputStream.read() 不释放。 由服务器关闭套接字是不正常的。情况完全对称。任何一端都可能关闭,然后另一端会得到 -1 或 null 或 EOFException,具体取决于它调用的方法。 @James,好的,但我对关闭哪个套接字感到困惑。现在更清楚了。我用 java 1.5.0.20 在我的机器(Ubuntu 9.10)上运行了你的代码,它没有阻塞。我在每个客户端连接处都看到“中断”。 @EJP 确实它是对称的,但如果服务器不依赖客户端关闭套接字会更好。【参考方案2】:您发布的服务器代码未检查 -1。所以要么是问题所在,要么不是真正的代码,在这种情况下,您应该发布真正的代码以供评论。
编辑您发布的代码与您描述的不符。
【讨论】:
您的代码对我有用。并且关闭由在 read() 中阻塞的同一 JVM 创建的套接字不会导致 read() 返回 -1,它会导致 IOException。 很奇怪。它对我不起作用。我正在使用 android 设备关闭套接字。也许这就是问题所在?我将尝试与计算机连接并关闭()。 对安卓一无所知,但关闭套接字应该发送一个 TCP FIN,它作为 EOS 被对等方接收。如果它不这样做,那就是一个错误。你能嗅探网络吗?那将是我的下一步。但我担心您的说法,即在服务器上关闭会导致服务器的 read)) 方法返回-1。它没有。你确定你看到了吗?我想知道您是否正在运行您认为正在运行的代码。 我想说的是,如果我关闭套接字服务器端。客户端中的 read() 方法(是的,我在客户端中有一个)返回 -1 就像它应该的那样。 好的,我在我的工作站上编写了我的 android 设备的模拟代码,它工作正常。套接字关闭并返回-1。一定是安卓的bug?我注意到如果我杀了我的 android 应用程序,它确实会像它应该的那样关闭。但不是用 close()【参考方案3】:在你的 Android 客户端代码中试试这个:
socket.shutdownOutput();
socket.close();
应该会更好;-)
【讨论】:
不,完全一样。 shutdown() 发送一个 FIN,如果它还没有发送, close() 发送一个 FIN。 这对我有用。我使用的是 nodejs 后端,并且 java 在没有关闭线的情况下不会发送关闭信号。以上是关于在客户端 JAVA 中调用 socket.close() 时,套接字未关闭服务器端的主要内容,如果未能解决你的问题,请参考以下文章
怎样在java 中调用web service 传入参数返回xml?