java.nio.channels.ServerSocketChannel未正确关闭

时间:2014-04-04 18:07:03

标签: java sockets garbage-collection nio

我有一个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();
}               

当我从客户端发送第一条消息时,它已成功传送到服务器,客户端程序退出。然后麻烦开始了。当我再次初始化客户端并尝试 建立在与我第一次做的服务器相同的端口和地址,我得到了

  

java.net.BindException:已在使用的地址:connect

即使我关闭了相关的通道/套接字,也会出现

异常。 我一直在更新ServerSocketChannelInetSocketAddress对象,因为我的客户端实例必须在写入后关闭,我必须解除该通道,因为我关闭后无法重用通道,必须每次都制作一个新的物体。我的理论是因为channel引用每次都被重新分配,孤立的对象变成GC肉,但由于close()方法显然不能正常工作,因此通道仍处于活动状态,直到GC收集它,我的端口将是挤兑。 尽管如此,我尝试在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
 }              

为清楚起见,以下是我从客户端连接的方式:

        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();

3 个答案:

答案 0 :(得分:3)

看起来你会混淆客户端和服务器。通常,服务器只启动一次,bind到s端口。通常,当程序退出时,端口被释放时,不需要close。显然,您必须关闭Socket获得的ServerSocket.accept(),但这是另一个故事。

我猜你已经被你的变量名混淆了(就像我刚开始的时候一样)。尝试根据他们的类型打电话给所有的东西,这里匈牙利人对我很有帮助。


我为测试而写的code是漫长的,愚蠢的,无聊的。但似乎有效。

答案 1 :(得分:0)

这样做可能也有帮助:

channel.setOption(StandardSocketOptions.SO_REUSEADDR,true);

搜索有关此选项的信息以了解更多信息。

答案 2 :(得分:-3)

对GC客户端套接字执行ch.close()。