【问题标题】:Adobe Air - How to detect LAN servers (listening to a specific port)Adobe Air - 如何检测 LAN 服务器(监听特定端口)
【发布时间】:2014-01-14 11:23:16
【问题描述】:

我想知道如何检测 LAN 服务器。

我制作了一个客户端/服务器应用程序,一切正常,但您必须手动输入服务器的 IP 地址。

目前我正在尝试在客户端/服务器上使用DatagramSocket。 服务器将发送一个包含其 IP 地址的数据包,以便客户端可以连接到该地址。数据包将其发送到其本地广播 IP (192.168.1.255) 端口 4444。

客户端会监听4444端口,然后接收数据包。

如果我在同一台计算机上,这可以工作(所以我的代码没有问题),但当我在另一台计算机上尝试并尝试连接到我的计算机时则不行。

我对网络不是很熟悉,所以我希望有人可以向我解释如何正确地做到这一点。

另外,在 255.255.255.255 上的 AIR 广播中不支持:Note: Sending data to a broadcast address is not supported.source

【问题讨论】:

    标签: actionscript-3 flash networking air udp


    【解决方案1】:

    要发现 LAN 中的其他计算机,您的服务器必须发送 UDP 广播,AIR 不支持这种广播。如果您的服务器必须在 AIR 中实现,您可以使用原生扩展 (android/ios) 或通过执行 UDP 广播的 NativeProcess(桌面)调用系统进程。

    以下是一些可能有用的链接:

    http://lucamezzalira.com/2011/07/29/multicast-udp-socket-in-adobe-air-with-python/

    https://github.com/wouterverweirder/AIR-Mobile-UDP-Extension

    【讨论】:

    • 感谢您让我知道没有其他来源是不可能的。
    • 我什至不确定 AIR 是否可以接收广播。对我来说,一开始的人似乎必须使用 phyton 脚本接收广播,然后将其转发到同一台机器上的单播端口,实际的 AIR 客户端在该端口进行监听。
    【解决方案2】:

    为了实现这一点,我创建了自己的解决方案(这并不完美,但我能想到的唯一工作方式)。

    在服务器端,我创建了一个新的 DatagramSocket,它将向特定范围内的每个 IP 地址发送一条消息。

    import flash.utils.setInterval;
    import flash.utils.clearInterval;
    ....
    
        private const subnetMask:Array = NetworkUtil.getSubnetMask(NetworkUtil.getPrefixLength());
        private const ip:Array = NetworkUtil.getIpAddress().split(".");
        private const ipBroadcastSocket:DatagramSocket = new DatagramSocket();
        private static var _broadcastIp:Boolean;
        private static var intervalId:int;
        ....
        {
        ....
            intervalId = setInterval(broadcastIP, 2000, NetworkUtil.getIpAddress());//broadcast the servers Ip-Address every 2 seconds
        }
    
        private function broadcastIP(message:String):void
        {
            if(_broadcastIp){
                try
                {
                    if(subnetMask[1] != 255 || subnetMask[2] != 255){
                        trace("!!! WARNING: NOT A 'C' CLASS NETWORK !!! (Will not broadcast IP.)");
                        clearInterval(intervalId);
                    }
                    else
                    {
                        var data:ByteArray = new ByteArray();
                        data.writeUTFBytes(message);
    
                        for(var i4:int = subnetMask[3]; i4 <= 255; i4++){
                            var tempIp:String = ip[0] + "." + ip[1] + "." + ip[2] + "." + (subnetMask[3] == 255 ? ip[3] : i4);
                            if(tempIp != NetworkUtil.getBroadcastIp() && tempIp != NetworkUtil.getSubnetIp(ip, subnetMask)){
                                serverDatagramSocket.send(data, 0, 0, tempIp, port);
                            }
                        }
                    }
                }
                catch (error:Error)
                {
                    trace(error.message);
                }
            }
        }
    

    然后在客户端,添加另一个DatagramSocket。然后将其绑定到服务器使用的同一个端口,并将其设置为接收模式。

    private var ipBroadcastSocket:DatagramSocket = new DatagramSocket();
    ipBroadcastSocket.bind(4444);
    ipBroadcastSocket.addEventListener(DatagramSocketDataEvent.DATA, dataReceived);
    ipBroadcastSocket.receive();
    
    private function dataReceived(e:DatagramSocketDataEvent):void
    {
        var data:String = e.data.readUTFBytes(e.data.bytesAvailable);
        trace("Server found with IP: "+ data);
    }
    

    这是我的网络实用程序类,供那些想要实现此功能的人使用:

    import flash.net.InterfaceAddress;
    import flash.net.NetworkInfo;
    import flash.net.NetworkInterface;
    
    public class NetworkUtil
    {
        private static var address:InterfaceAddress;
    
        {//static constructor
            getAddress(); //Get the adress of this host
        }
    
        public static function getAddress():void
        {
            var interfaceVector:Vector.<NetworkInterface> = NetworkInfo.networkInfo.findInterfaces();
            for each (var networkInt:NetworkInterface in interfaceVector) {
                if (networkInt.active && networkInt.displayName.toLowerCase() != "hamachi") { //Ignore the hamachi interface
                    for each (var addresss:InterfaceAddress in networkInt.addresses) {
                        if (addresss.ipVersion == "IPv4") {
                            if(addresss.address != "127.0.0.1"){
                                trace(networkInt.displayName); //Output ipAdress for debugging
                                address = addresss;
                            }
                        }
                    }
                }
            }
        }
    
        public static function getPrefixLength():int
        {
            return address.prefixLength;
        }
    
        public static function getBroadcastIp():String
        {
            return address.broadcast;
        }
    
        public static function getIpAddress():String
        {
            return address.address;
        }
    
        public static function getSubnetIp(currentIp:Array, subnetMask:Array):String
        {           
            for(var i:int; i < 4; i++){
                currentIp[i] = (subnetMask[i] == 255 ? currentIp[i] : 0);
            }
    
            return currentIp[0] + "." + currentIp[1] + "." + currentIp[2] + "." + currentIp[3];
        }
    
        public static function getAmountOfHosts(prefixLength:int):int
        {
            return (256 << (24-prefixLength)) -2;
        }
    
        public static function getSubnetMask(prefixLength:int):Array
        {
            var subnetMask:Array = [];
    
            for(var i:int = 0; i < 4; i++){
                var subnet:uint = 255;
                if(prefixLength >= 8){
                    prefixLength-=8;
                }else{
                    subnet = 255 - (255 >> prefixLength);
                    prefixLength=0;
                }
    
                subnetMask[i] = subnet;
            }
            return subnetMask;
        }
    
        public static function isValidIp(ip:String):Boolean {
            ip = ip.replace( /\s/g, ""); //remove spaces for checking
            var pattern:RegExp = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
    
            if(pattern.test(ip)){
                var octets:Array = ip.split(".");
                if (parseInt(String(octets[0])) == 0) {
                    return false;
                }
                if (parseInt(String(octets[3])) == 0) {
                    return false;
                }
                return true;
            }
            return false;
        }
    }
    

    【讨论】:

    • 我正在尝试实现这一点。请原谅我的无知,但您能解释一下子网掩码的工作原理吗?
    • @user5839 是的,当然。我已经实现了它来检查您当前所在的网络类型。如果是 A 或 B 网络,则要发送的数据包数量过多,结果是无法找到服务器。我已经添加了网络工具类我的答案。我用它来获取子网掩码。你可以这样使用它:NetworkUtil.getSubnetMask(NetworkUtil.getPrefixLength());
    【解决方案3】:

    虽然您可以在 Windows 系统上使用 192.168.0.255,但在 MacOS X 上会出现异常。相反,您可以在 MacOS X 上使用 D 类 IP 广播 ... 224.0.0.1

    【讨论】:

      猜你喜欢
      • 2011-09-14
      • 2011-06-27
      • 1970-01-01
      • 2012-03-30
      • 1970-01-01
      • 1970-01-01
      • 2019-03-30
      • 2016-01-07
      • 1970-01-01
      相关资源
      最近更新 更多