在客户端 JAVA 中调用 socket.close() 时套接字未关闭服务器端

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3303628/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 01:12:48  来源:igfitidea点击:

Socket not closing serverside when calling socket.close() in client JAVA

javasocketsmultithreadinginputstream

提问by James Ford

I'm having problems with sockets in java. I have a ServerSocketthat is listening with accept() and spawns threads for each client-request. Communication between clients and the server works fine. I am using an inputstream to read data from clients in the serverthreads, like:

我在 java 中遇到套接字问题。我有一个ServerSocket正在侦听 accept() 并为每个客户端请求生成线程。客户端和服务器之间的通信工作正常。我正在使用输入流从服务器线程中的客户端读取数据,例如:

inputStream = mySocket.getInputStream();
bytes = inputStream.read(buffer);

My problem is that if I call socket.close() from the clients, nothing happens to the blocking call of bytes = inputStream.read(buffer);, it continues to block. But it works if I close the socket from the server, then the inputStream.read(buffer);of the client returns "-1".

我的问题是,如果我从客户端调用 socket.close(), 的阻塞调用没有任何反应bytes = inputStream.read(buffer);,它会继续阻塞。但是如果我从服务器关闭套接字,它就会工作,然后inputStream.read(buffer);客户端的返回“-1”。

SERVER-MAINTHREAD:

服务器-主线程:

//SERVER MAIN THREAD, SPAWNS CLIENT THREADS
ServerSocket serverSocket = new ServerSocket(SERVERPORT);
while (listening){

new ServerThread(serverSocket.accept(), monitor).start();
}

SERVER-CLIENTTHREADS:

服务器-客户端线程:

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;
            }
        }
    }

CLIENT:

客户:

InetAddress serverAddr = InetAddress.getByName("serverhostname");

socket = new Socket(serverAddr, PORT);

socket.close(); //Close the socket connection from client. Nothing happens in the serverthread

回答by user207421

The server code you posted doesn't check for -1. So either that is the problem or that isn't the real code, in which case you should post the realcode for comment.

您发布的服务器代码不会检查 -1。所以要么这是问题,要么不是真正的代码,在这种情况下,您应该发布真正的代码以供评论。

EDITThe code you have posted does not behave as you have described.

编辑您发布的代码与您描述的不符。

回答by openkwaky

Try this in your Android client code :

在您的 Android 客户端代码中试试这个:

socket.shutdownOutput(); 
socket.close(); 

It should be better ;-)

应该会更好;-)

回答by Bruno Thomas

I don't know if I understand your issue, but I would say that it is normal that it's up to the server to close the socket.

我不知道我是否理解您的问题,但我会说由服务器关闭套接字是正常的。

On server side (in an independent thread) you have the listening socket :

在服务器端(在一个独立线程中)你有监听套接字:

ServerSocket socketServeur = new ServerSocket(port);

Then probably (in the same thread if it is a small server) a loop accepting incoming connections (no exception management, probably the socket.close is in a finally block) :

然后可能(在同一个线程中,如果它是一个小型服务器)接受传入连接的循环(没有异常管理,可能 socket.close 在一个 finally 块中):

while (! askedToClose) {
    Socket socket = socketServeur.accept();
    doSomethingWithRequest(socket);
    socket.close();
}

On the client side, you have :

在客户端,您有:

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

The server should know when it has reached the end of the request. For example in http it could be (taken from a mockHttpServer in scala so there might be some errors but the process is the same):

服务器应该知道它何时到达请求的末尾。例如,在 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();
}

EDIT : I read the code added and I still don't get it :

编辑:我阅读了添加的代码,但我仍然不明白:

  • you call Socket.close(), but this method is not static
  • you loop forever in the "server"
  • I have the impression that you use the same socket for client and server
  • 你调用了 Socket.close(),但是这个方法不是静态的
  • 你永远在“服务器”中循环
  • 我的印象是您对客户端和服务器使用相同的套接字

You have 3 "sockets" :

你有 3 个“插座”:

  • the listening socket (object ServerSocket)
  • the accept socket (Object Socket sent by socketServer.accept())
  • the client socket (like above in the example)
  • 侦听套接字(对象 ServerSocket)
  • 接受套接字(由 socketServer.accept() 发送的对象套接字)
  • 客户端套接字(如上例所示)

The server open and close listening and "accept" socket, and should have no impact of bad client socket management.

服务器打开和关闭侦听和“接受”套接字,并且应该不会受到坏客户端套接字管理的影响。

Then if you want your server to accept several concurrent connections, you may add a ThreadPool for accepting connections and treating requests and responses.

然后,如果您希望您的服务器接受多个并发连接,您可以添加一个线程池来接受连接并处理请求和响应。