当前位置: 首页 > 知识库问答 >
问题:

Java、Netty、TCP和UDP连接集成:UDP连接没有可用的缓冲区空间

上官季
2023-03-14

我有使用TCP和UDP协议的应用程序。主要假设客户端通过TCP协议连接到服务器端,当连接建立后,发送UDP数据报。我必须支持两种连接到服务器的方案:-客户端在服务器运行时连接-客户端在服务器关闭时连接并重试连接直到服务器重新启动

java.net.SocketException: No buffer space available (maximum connections reached?): bind
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:344)
at sun.nio.ch.DatagramChannelImpl.bind(DatagramChannelImpl.java:684)
at sun.nio.ch.DatagramSocketAdaptor.bind(DatagramSocketAdaptor.java:91)
at io.netty.channel.socket.nio.NioDatagramChannel.doBind(NioDatagramChannel.java:192)
at io.netty.channel.AbstractChannel$AbstractUnsafe.bind(AbstractChannel.java:484)
at io.netty.channel.DefaultChannelPipeline$HeadContext.bind(DefaultChannelPipeline.java:1080)
at io.netty.channel.AbstractChannelHandlerContext.invokeBind(AbstractChannelHandlerContext.java:430)
at io.netty.channel.AbstractChannelHandlerContext.bind(AbstractChannelHandlerContext.java:415)
at io.netty.channel.DefaultChannelPipeline.bind(DefaultChannelPipeline.java:903)
at io.netty.channel.AbstractChannel.bind(AbstractChannel.java:197)
at io.netty.bootstrap.AbstractBootstrap$2.run(AbstractBootstrap.java:350)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
at java.lang.Thread.run(Thread.java:722)

在下面我附上类的源代码。所有源代码来自放置在官方Netty项目页面中的示例。我唯一误解的是我用非静态变量和函数替换了静态变量和函数。这导致了以后我将需要到多个服务器的许多TCP-UDP连接。

public final class UptimeClient {
static final String HOST = System.getProperty("host", "192.168.2.193");
static final int PORT = Integer.parseInt(System.getProperty("port", "2011"));
static final int RECONNECT_DELAY = Integer.parseInt(System.getProperty("reconnectDelay", "5"));
static final int READ_TIMEOUT = Integer.parseInt(System.getProperty("readTimeout", "10"));

private static UptimeClientHandler handler;

public void runClient() throws Exception {
    configureBootstrap(new Bootstrap()).connect();
}

private Bootstrap configureBootstrap(Bootstrap b) {
    return configureBootstrap(b, new NioEventLoopGroup());
}

@Override
protected Object clone() throws CloneNotSupportedException {
    return super.clone(); //To change body of generated methods, choose Tools | Templates.
}

Bootstrap configureBootstrap(Bootstrap b, EventLoopGroup g) {
    if(handler == null){
            handler = new UptimeClientHandler(this);
    }
    b.group(g)
     .channel(NioSocketChannel.class)
     .remoteAddress(HOST, PORT)
     .handler(new ChannelInitializer<SocketChannel>() {
        @Override
        public void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(new IdleStateHandler(READ_TIMEOUT, 0, 0), handler);
        }
     });

    return b;
}

void connect(Bootstrap b) {
    b.connect().addListener(new ChannelFutureListener() {
        @Override
        public void operationComplete(ChannelFuture future) throws Exception {
            if (future.cause() != null) {
                handler.startTime = -1;
                handler.println("Failed to connect: " + future.cause());
            }
        }
    });
}
}


@Sharable
public class UptimeClientHandler extends SimpleChannelInboundHandler<Object> {
UptimeClient client;
public UptimeClientHandler(UptimeClient client){
    this.client = client;
}
long startTime = -1;

@Override
public void channelActive(ChannelHandlerContext ctx) {
    try {
        if (startTime < 0) {
            startTime = System.currentTimeMillis();
        }
        println("Connected to: " + ctx.channel().remoteAddress());
        new QuoteOfTheMomentClient(null).run();
    } catch (Exception ex) {
        Logger.getLogger(UptimeClientHandler.class.getName()).log(Level.SEVERE, null, ex);
    }
}

@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
}

@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
    if (!(evt instanceof IdleStateEvent)) {
        return;
    }

    IdleStateEvent e = (IdleStateEvent) evt;
    if (e.state() == IdleState.READER_IDLE) {
        // The connection was OK but there was no traffic for last period.
        println("Disconnecting due to no inbound traffic");
        ctx.close();
    }
}

@Override
public void channelInactive(final ChannelHandlerContext ctx) {
    println("Disconnected from: " + ctx.channel().remoteAddress());
}

@Override
public void channelUnregistered(final ChannelHandlerContext ctx) throws Exception {
    println("Sleeping for: " + UptimeClient.RECONNECT_DELAY + 's');

    final EventLoop loop = ctx.channel().eventLoop();
    loop.schedule(new Runnable() {
        @Override
        public void run() {
            println("Reconnecting to: " + UptimeClient.HOST + ':' + UptimeClient.PORT);
            client.connect(client.configureBootstrap(new Bootstrap(), loop));
        }
    }, UptimeClient.RECONNECT_DELAY, TimeUnit.SECONDS);
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    cause.printStackTrace();
    ctx.close();
}

void println(String msg) {
    if (startTime < 0) {
        System.err.format("[SERVER IS DOWN] %s%n", msg);
    } else {
        System.err.format("[UPTIME: %5ds] %s%n", (System.currentTimeMillis() - startTime) / 1000, msg);
    }
    }
}

public final class QuoteOfTheMomentClient {

private ServerData config;
public QuoteOfTheMomentClient(ServerData config){
    this.config = config;
}

public void run() throws Exception {


    EventLoopGroup group = new NioEventLoopGroup();
    try {
        Bootstrap b = new Bootstrap();
        b.group(group)
         .channel(NioDatagramChannel.class)
         .option(ChannelOption.SO_BROADCAST, true)
         .handler(new QuoteOfTheMomentClientHandler());

        Channel ch = b.bind(0).sync().channel();

        ch.writeAndFlush(new DatagramPacket(
                Unpooled.copiedBuffer("QOTM?", CharsetUtil.UTF_8),
                new InetSocketAddress("192.168.2.193", 8193))).sync();

        if (!ch.closeFuture().await(5000)) {
            System.err.println("QOTM request timed out.");
        }
    }
    catch(Exception ex)
    {
        ex.printStackTrace();
    }
    finally {
        group.shutdownGracefully();
    }
    }
}

public class QuoteOfTheMomentClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {

@Override
public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
    String response = msg.content().toString(CharsetUtil.UTF_8);
    if (response.startsWith("QOTM: ")) {
        System.out.println("Quote of the Moment: " + response.substring(6));
        ctx.close();
    }
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    cause.printStackTrace();
    ctx.close();
    }
}

共有1个答案

蓬琦
2023-03-14

如果您的服务器是Windows server 2008(R2或R2 SP1),则此问题很可能由此stackoverflow答案描述并解决,该答案引用了Microsoft知识库文章#2577795

发生此问题的原因是WinSock的辅助函数驱动程序(Afd.sys)中存在竞争条件,导致套接字泄漏。随着时间的推移,如果所有可用的套接字资源都耗尽了,就会出现“症状”部分中描述的问题。

如果您的服务器是Windows Server2003,此问题很可能由此stackoverflow答案描述并解决,该答案引用了Microsoft知识库文章#196271

在“应用于”部分中包含的产品中,临时TCP端口的默认最大数量为5000。在这些产品中增加了一个新的参数。要增加临时端口的最大数量,请执行以下步骤...

...这基本上意味着您的临时端口已用完。

 类似资料:
  • 问题内容: 我在linux上有一个Java应用程序,它可以打开UDP套接字并等待消息。 在高负载下运行了几个小时之后,有一个数据包丢失,即数据包被内核接收,但不是由我的应用程序接收(我们在嗅探器中看到丢失的数据包,在netstat中看到UDP数据包丢失,我们没有看到这些数据包)在我们的应用日志中)。 我们尝试扩大套接字缓冲区,但这并没有帮助-我们早些时候就开始丢失数据包,仅此而已。 对于调试,我想

  • 问题内容: 嗨,我正在使用Apache HTTP Client 4.0基于HTTPS协议在服务器上上传一些文件。上载的应用程序每天24x7运行。今天突然间,它开始抛出此异常- 谁能帮帮我吗?我完全不知道发生了什么事? 这是上传文件的源代码- 问题答案: 我的猜测:端口用尽了,这个问题与您的代码不直接相关,而与服务器的当前状态有关。与其他计算机的连接过多,这会导致问题。 要找什么: 服务器的使用率是

  • 我正在Linux上编写一个C应用程序。我的应用程序有一个 UDP 服务器,它在某些事件上向客户端发送数据。UDP 服务器还会收到来自客户端的一些反馈/确认。 为了实现这个应用程序,我使用了一个UDP套接字(例如< code>int fdSocket)来发送和接收来自所有客户端的数据。我将这个socked绑定到端口8080,并将套接字设置为非阻塞模式。 我创建了两个线程。在一个线程中,我等待某个事件

  • 我有一个简单的udp客户机/服务器程序。 如果客户端正在失去连接,或者服务器正在重新启动,客户端不会自动重新连接。我总是要手动重启客户端。 这是我的客户端套接字配置:

  • 我正在为一个大学项目创建一个游戏服务器,所以我不使用任何库/框架。 经过大量研究后,我希望客户端和服务器使用UDP协议进行大量通信,例如角色移动和计时器,因为这方面的可靠性并不重要,丢失的数据包可以得到补偿。 但是,我还想将TCP协议用于游戏的其他方面,例如操作和事件,在这些方面,信息到达客户端是至关重要的。 我的问题是,我对使用UDP不太了解,在Java,从我的理解来看,它完全不同于仅仅为TCP

  • TCP是传输控制协议,UDP是用户数据表协议; TCP长连接,UDP无连接; UDP程序结构较简单,只需发送,无须接收; TCP可靠,保证数据正确性、顺序性;UDP不可靠,可能丢数据; TCP适用于少量数据,UDP适用于大量数据传输; TCP速度慢,UDP速度快;