netty绑定端口时只能绑定外网地址

我在云服务器上使用netty中,在进行端口绑定时,调用ServerBootstrapbind(String inetHost, int inetPort)方法时,如果inetHost参数填写公网ip,在启动时就报错java.net.BindException: Cannot assign requested address,参数换成127.0.0.1或者0.0.0.0就没事,这是什么原因导致的啊?
一开始我们是在学校服务器上开发,一直都填的内网ip,无法公网访问,最近放假了老师让我把服务器转移到云上,结果就死活启动不了,现在问题解决了,就是不知道为啥不能绑定公网ip

阅读 13.8k
4 个回答
  1. 如果inetHost参数填写公网ip,填写的什么IP?
  2. 服务器是什么供应商的?阿里云?腾讯云?
  3. 服务器执行ifconfig截图贴一下

用ifconfig查一下机器ip,开你所说的外网ip在不在网卡配置里面
可能在云上,你所说的公网IP不是你机器上的IP,而是公网IP映射到你云服务器上的IP,所以,你用netty绑定IP就失败了

虽然已经采纳了答案,但我还是想回答一下这个问题。

首先,对于一个程序来讲,它所绑定的IP只能是其所在机器(无论物理机还是虚拟机)上的某个网卡的IP地址,这个你可以到机器上运行ifconfig查看。

其次,所谓绑定的含义是规定程序能够监听到哪个目的地IP的IP包,比如机器有两个网卡A和B,IP地址分别是AIP和BIP,你的程序绑定AIP,那么操作系统只会将目的地是AIP的IP包转发给你的程序。0.0.0.0是特殊的,它代表着能够转发目的地IP是机器上任意IP的IP包到你的程序。

最后,为何可以通过公网IP访问到你的机器?这是因为云服务商给你做了NAT,而这个地址你的机器是不知道的,也不属于你的机器上的任意一张网卡,所以你无法绑定。

PS. 你应该去学一些基础网络知识。可以找一本CCNA或者HCNA的书看看。

Netty的引导类为应用程序的网络层配置提供了容器,这涉及将一个进程绑定到某个指定的端口,或者将一个进程连接到另一个运行在某个指定主机的指定端口上的进程。
“服务器”和“客户端”实际上表示了不同的网络行为:是监听传入的连接还是建立到一个或者多个进程的连接。
面向连接的协议:请记住,严格来说,“连接”这个属于仅适用于面向连接的协议,如TCP、其保证了两个连接端点之间消息的有序传递。
因此,有两种类型的引导:一种用于客户端(简单称为Bootstrap),而另一种(ServerBootstrap)用于服务器。无论你的应用程序使用哪些协议或者处理哪种类型的数据,唯一决定它使用哪种引导类的是它是作为一个客户端还是作为一个服务器。
图片描述
这两种类型的引导类之间的第一个区别已经讨论过了:ServerBootstrap将绑定到一个端口,因为服务器必须要监听连接,而Bootstrap则由想要连接到远程节点的客户端应用程序所使用的

代码案例:使用NIO TCP传输的客户端

EventLoopGroup group = new NioEventLoopGroup();
        //创建一个Bootstrap类的实例以创建和连接新的客户端Channel
        Bootstrap bootstrap = new Bootstrap();
        //设置EventLoopGroup,提供用于处理Channel事件的EventLoop
        bootstrap.group(group)
                //指定要使用的Channel实现
                .channel(NioSocketChannel.class)
                //指定用于Channel事件和数据的ChannelInboundHandler
                .handler(new SimpleChannelInboundHandler<ByteBuf>() {
                    @Override
                    protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf)
                            throws Exception {
                        System.out.println("Received data");
                    }
                });
        ChannelFuture future = bootstrap.connect(
                //连接到远程主机
                new InetSocketAddress("www.myself.com",80)
        );
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()){
                    System.out.println("Connection established");
                } else {
                    System.out.println("Connection attempt failed");
                    channelFuture.cause().printStackTrace();
                }
            }
        });

实现服务器引导

NioEventLoopGroup group = new NioEventLoopGroup();
        //创建ServerBootstrap
        ServerBootstrap bootstrap = new ServerBootstrap();
        //设置EventLoopGroup,其提供了用于处理Channel事件的EventLoop
        bootstrap.group(group)
                //指定要使用的Channel实现
                .channel(NioServerSocketChannel.class)
                .childHandler(new SimpleChannelInboundHandler<ByteBuf>() {
                    @Override
                    protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf)
                            throws Exception {
                        System.out.println("Received data");
                    }
                });
        //通过配置好的ServerBootstrap的实例绑定该Channel
        ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080));
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()){
                    System.out.println("Server bound");
                } else {
                    System.out.println("Bound attempt failed");
                    channelFuture.cause().printStackTrace();
                }
            }
        });

客户端引导

//创建ServerBootstrap以创建和绑定新的Channel
        ServerBootstrap bootstrap = new ServerBootstrap();
        //设置EventLoopGroup,其将提供用以处理Channel事件的EventLoop
        bootstrap.group(new NioEventLoopGroup(),new NioEventLoopGroup())
                //指定Channel的实现
                .channel(NioServerSocketChannel.class)
                //注册一个ChannelInitializerImpl的实例来设置ChannelPipeline
                .childHandler(new ChannelInitializerImpl());
        ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080));
        future.sync();*/

        /*//创建一个AttributeKey以标识该属性
        final AttributeKey<Integer> id = AttributeKey.valueOf("ID");
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(new NioEventLoopGroup())
                .channel(NioSocketChannel.class)
                .handler(new SimpleChannelInboundHandler<ByteBuf>() {
                    @Override
                    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
                        //使用AttributeKey检索属性以及它的值
                        Integer idValue = ctx.channel().attr(id).get();
                        //do something with the idValue
                    }

                    @Override
                    protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf)
                            throws Exception {
                        System.out.println("Received data");
                    }
                });
        //设置ChannelOption其将在connect()或者bind()方法被调用时被设置到已经创建的Channel上
        bootstrap.option(ChannelOption.SO_KEEPALIVE,true)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,5000);
        //存储该id属性
        bootstrap.attr(id,123456);
        ChannelFuture future = bootstrap.connect(new InetSocketAddress("www.myself.com",80));
        future.syncUninterruptibly();
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题