简体   繁体   English

java.nio.channels.ServerSocketChannel无法正确关闭

[英]java.nio.channels.ServerSocketChannel not closing properly

I have a java.nio.channels.ServerSocketChannel which I initialised as follows: 我有一个java.nio.channels.ServerSocketChannel ,其初始化如下:

while(true)
{
    ServerSocketChannel channel = ServerSocketChannel.open();
    InetSocketAddress serverSocket = new InetSocketAddress(host,port);
    channel.bind(serverSocket);
    SocketChannel ch = channel.accept();

    // Later on when I have read off data from a client, I want to shut this 
    // connection down and restart listening.
    channel.socket().close(); //Just trying to close the associated socket 
    // too because earlier approaches failed
    channel.close();
}               

When I send the first message from client it is successfully delivered to server and the client program exits . 当我从客户端发送第一条消息时,它已成功传递到服务器,并且客户端程序退出 Then trouble begins. 然后麻烦开始了。 When I initialise the client again and try to establish at the same port and address of the server as I did the first time, I get a 当我再次初始化客户端并尝试建立与第一次相同的服务器端口和地址时,

java.net.BindException: Address already in use: connect java.net.BindException:地址已在使用中:connect

exception even though I closed the associated channel/socket. 即使我关闭了关联的通道/套接字也是如此。 I have been renewing the ServerSocketChannel and InetSocketAddress objects because as my client instance has to shut down after a write, I have to disengage that channel and since I cannot reuse a channel after it has been closed, I have to make a new object everytime. 我一直在更新ServerSocketChannelInetSocketAddress对象,因为在写入之后我的客户端实例必须关闭,因此我必须脱离该通道,并且由于关闭该通道后无法重用该通道,因此每次都必须创建一个新对象。 My theory is since the channel reference is reassigned each time, the orphaned object becomes GC meat, but since the close() method apparently is not working properly, the channel is still alive and until GC collects it my port will be hogged. 我的理论是,由于每次都重新分配channel引用,孤立的对象变成GC的主角,但是由于close()方法显然无法正常工作,通道仍然有效,直到GC收集到我的端口为止。 Nevertheless I tried keeping the initialisation of ServerSocketChannel and InetSocketAddress objects before the while loop, but this did not help, and the same exception occurred after the first write, as before. 尽管如此,我还是尝试在while循环之前保留ServerSocketChannelInetSocketAddress对象的初始化,但这并没有帮助,并且第一次写入后发生了与以前相同的异常。

 ServerSocketChannel channel = ServerSocketChannel.open();
 InetSocketAddress serverSocket = new InetSocketAddress(host,port);
 channel.bind(serverSocket);

 while (true)
 {
    SocketChannel ch = channel.accept();
    //read from a client
 }              

For clarity , here is how I connect from the client: 为了清楚起见,这是我如何从客户端进行连接:

        SocketChannel ch=SocketChannel.open();
        ch.bind(new InetSocketAddress("localhost", 8077));
        InetSocketAddress address=new InetSocketAddress("localhost",8079);
                    //the address and port of the server
        System.out.print(ch.connect(address));
        ByteBuffer buf=ByteBuffer.allocate(48);
        buf.clear();
        buf.put("Hellooooooooooooooooooooooooo".getBytes());
        buf.flip();
        while(buf.hasRemaining()) {
            ch.write(buf);
        }
        ch.close();

It looks like you're confusing client and server. 看来您在混淆客户端和服务器。 Normally, server starts only once and bind s to s port. 通常,服务器仅启动一次并将s bind到s端口。 Usually, there's no need to close there anything as the port gets freed when the program exits. 通常,由于程序退出时端口被释放,因此无需close任何内容。 Obviously, you must close the Socket s obtained by ServerSocket.accept() , but that's another story. 显然,您必须关闭由ServerSocket.accept()获得的Socket ,但这是另一回事了。

I guess you've got confused by your variable names (just like it happened to me as I started with this). 我想您对变量名感到困惑(就像我刚开始时遇到的那样)。 Try to call all things according to their type, here was Hungarian really helpful for me. 尝试根据事物的类型来调用所有事物,这对匈牙利人真的很有帮助。


The code I wrote for testing this is long, stupid, and boring. 我为测试此代码而编写的代码又长又笨又无聊。 But it seems to work. 但这似乎有效。

It may also be helpful to do: 这样做可能也会有所帮助:

channel.setOption(StandardSocketOptions.SO_REUSEADDR, true); channel.setOption(StandardSocketOptions.SO_REUSEADDR,true);

Search for information about this option to learn more. 搜索有关此选项的信息以了解更多信息。

还要执行ch.close()来GC客户端套接字。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM