可靠的服务发现问题

时间:2013-05-25 04:25:45

标签: java android service tcp

我正在把头撞在墙上。它有效,但不起作用。

让我澄清一下,测试是在LG Optimus G,A Galaxy S4和联想平板电脑上运行4.1 +

我在每个设备上启动一个服务器,每个设备在一个端口上自己广播,当用户点击发送时,所有已经解析了服务并且服务没有丢失的设备,一个线程将循环启动其他线程连接到自己广播的服务器,并发送数据。服务器接受传入连接,将其交给线程,然后重新打开。

所以回顾一下,每个设备都在广播服务器,每个设备都应该知道并跟踪其他服务器,当数据被发送时,所有已知服务器都会被命中。

我的问题是,在2/3设备中,可以始终与设备的自身建立连接。

两部手机,但一次只有一部,似乎知道另一部手机,并能够连接到另一部手机。即Galaxy S4可以向Optimus G打招呼,但是Optimus G除了自己或副歌之外不能说喜。

所以发现部分似乎不可靠,我不知道它是我,Android还是设备。我需要外面的眼睛。我试图以一种可以理解和深思熟虑的方式解决这个问题,我感谢任何对这个问题有所了解的人的帮助,因为我只是在网络世界中谦虚地开始,而且我更愿意从中学习有人。

我需要一种更可靠的方式来跟踪服务或发现它们,因为我的实现至少看起来有缺陷。

我感谢任何先进的帮助。 (我不相信这是一个像大多数其他机器人区域一样被踩踏的区域。)

这是完成初始化的地方。

/**initilize everything*/
private void buildNetwork()
{
    Log.d(TAG, "buildNetwork");
    networkHelper = new NetworkServiceDiscoveryHelper(this);
    networkHelper.initializeNsd(this);
    networkHelper.discoverServices();
    connectionReceiver = new ConnectionReceiver(this, this);
    // this next line launches the server thread which will obtain a socket
    // to be used in the finishBuildingNetwork()
    new Thread(connectionReceiver).start();

}

/** after the serversocket has been given a port we need to broadcast it*/
private void finishBuildingNetwork(int port)
{
    Log.d(TAG, "finishBuildingNetwork");
    networkHelper.registerService(port);
}

这是我对常见NSDManager助手类的一些改变。

public class NetworkServiceDiscoveryHelper
{

    public static final String TAG = "NetworkServiceDiscoveryHelper";
    public static final String KEY_DEVICE = "device";

    Context mContext;

    NsdManager mNsdManager;
    NsdManager.ResolveListener mResolveListener;
    NsdManager.DiscoveryListener mDiscoveryListener;
    NsdManager.RegistrationListener mRegistrationListener;

    public static final String SERVICE_TYPE = "_http._tcp.";

    public String mServiceName = "BlurbChat";

    NsdServiceInfo mService;

    private DiscoveredDevicesManager deviceManager;
    private NetworkDiscoveryHelperListener helperListener;

    /**
     * 
     * @param context
     *            - the activity context the service is to be attached to
     */
    public NetworkServiceDiscoveryHelper(Context context)
    {
        mContext = context;
        mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
        deviceManager = new DiscoveredDevicesManager();
    }

    /**
     * initialize the NetworkServiceDiscovery
     */
    public void initializeNsd(NetworkDiscoveryHelperListener helperListener)
    {
        this.helperListener = helperListener;

        initializeResolveListener();
        initializeDiscoveryListener();
        initializeRegistrationListener();

        // mNsdManager.init(mContext.getMainLooper(), this);

    }

    private void initializeDiscoveryListener()
    {
        mDiscoveryListener = new NsdManager.DiscoveryListener()
        {

            @Override
            public void onDiscoveryStarted(String regType)
            {
                Log.d(TAG, "Service discovery started");
                helperListener.SERVICE_STARTED(regType);
            }

            @Override
            public void onServiceFound(NsdServiceInfo service)
            {
                // A service was found! Do something with it.
                Log.d(TAG, "Service discovery success" + service);
                if (!service.getServiceType().equals(SERVICE_TYPE))
                {
                    // Service type is the string containing the protocol and
                    // transport layer for this service.
                    Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
                }
                else if (service.getServiceName().contains(mServiceName))
                {
                    // we have found our service! we use .contains because if
                    // there are multiple device with the same service being
                    // broadcast they will appear with name + (index)
                    // Resolve a discovered service. An application can resolve
                    // a service right before establishing a connection to fetch
                    // the IP and port details on which to setup the connection.
                    Log.d(TAG, "Found My Service Type: " + service.getServiceType() + service.getServiceName());
                    helperListener.SERVICE_FOUND(service);
                    mNsdManager.resolveService(service, mResolveListener);
                }

                /***************************************************************
                 * Checking the service name isn't always necessary, and is only relevant if you want to connect to a specific application.
                 * For instance, the application might only want to connect to instances of itself running on other devices. However, if the
                 * application wants to connect to a network printer, it's enough to see that the service type is "_ipp._tcp".
                 ******************************************************/
            }

            /**
             * when we lose our service
             */
            @Override
            public void onServiceLost(NsdServiceInfo service)
            {
                // When the network service is no longer available.
                Log.e(TAG, "service lost" + service);

                // remove the service
                if (deviceManager.removeDevice(service) != null)
                {
                    helperListener.SERVIVCE_LOST(service);
                }
            }

            /**
             * when our service is stopped
             */
            @Override
            public void onDiscoveryStopped(String serviceType)
            {
                Log.i(TAG, "Discovery stopped: " + serviceType);
                helperListener.DISCOVERY_STOPPED(serviceType);
            }

            @Override
            public void onStartDiscoveryFailed(String serviceType, int errorCode)
            {
                Log.e(TAG, "Discovery failed: Error code:" + errorCode);
                helperListener.DISCOVERY_START_FAILED(serviceType, errorCode);
                mNsdManager.stopServiceDiscovery(this);
            }

            @Override
            public void onStopDiscoveryFailed(String serviceType, int errorCode)
            {
                helperListener.DISCOVERY_STOP_FAILED(serviceType, errorCode);
                Log.e(TAG, "Discovery failed: Error code:" + errorCode);
                mNsdManager.stopServiceDiscovery(this);
            }
        };
    }

    private void initializeResolveListener()
    {
        mResolveListener = new NsdManager.ResolveListener()
        {

            @Override
            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode)
            {
                // Called when the resolve fails. Use the error code to debug.
                Log.e(TAG, "Resolve failed" + errorCode);
                helperListener.RESOLVE_FAILED(serviceInfo, errorCode);
            }

            @Override
            public void onServiceResolved(NsdServiceInfo serviceInfo)
            {
                Log.e(TAG, "Resolve Succeeded. " + serviceInfo);

                if (serviceInfo.getServiceName().equals(mServiceName))
                {
                    Log.d(TAG, "Same IP.");
                    return;
                }

                mService = serviceInfo;
                DiscoveredDevice device = new DiscoveredDevice(mService.getPort(), mService.getHost(), mService.getServiceName(), mService.getServiceType());
                deviceManager.addDevice(device);
                helperListener.RESOLVE_SUCCESS(serviceInfo);
            }
        };
    }

    private void initializeRegistrationListener()
    {
        mRegistrationListener = new NsdManager.RegistrationListener()
        {

            @Override
            public void onServiceRegistered(NsdServiceInfo serviceInfo)
            {
                mServiceName = serviceInfo.getServiceName();
                helperListener.SERVICE_REGISTERED(serviceInfo);
            }

            @Override
            public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode)
            {
                helperListener.SERVICE_REGISTRATION_FAILED(serviceInfo, errorCode);
            }

            @Override
            public void onServiceUnregistered(NsdServiceInfo serviceInfo)
            {
                helperListener.SERVICE_UNREGISTERED(serviceInfo);
            }

            @Override
            public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode)
            {
                helperListener.SERVICE_UNREGISTRATION_FAILED(serviceInfo, errorCode);
            }

        };
    }

    /**
     * To be called after initialize()
     * 
     * @param port
     *            - the port you would like to register/broadcast the service through.
     */
    public void registerService(int port)
    {
        NsdServiceInfo serviceInfo = new NsdServiceInfo();
        serviceInfo.setPort(port);
        serviceInfo.setServiceName(mServiceName);
        serviceInfo.setServiceType(SERVICE_TYPE);

        mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);

    }

    /**
     * Initiate service discovery to browse for instances of a service type. Service discovery consumes network bandwidth and will continue
     * until the application calls stopServiceDiscovery(NsdManager.DiscoveryListener).
     */
    public void discoverServices()
    {
        mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
    }

    /**
     * Stop service discovery initiated with discoverServices(String, int, NsdManager.DiscoveryListener). An active service discovery is
     * notified to the application with onDiscoveryStarted(String) and it stays active until the application invokes a stop service
     * discovery. A successful stop is notified to with a call to onDiscoveryStopped(String).
     */
    public void stopDiscovery()
    {
        mNsdManager.stopServiceDiscovery(mDiscoveryListener);
    }

    /**
     * 
     * @return - A class representing service information for network service discovery
     */
    public NsdServiceInfo getChosenServiceInfo()
    {
        return mService;
    }

    /**
     * Unregister a service registered through registerService(NsdServiceInfo, int, NsdManager.RegistrationListener). A successful
     * unregister is notified to the application with a call to onServiceUnregistered(NsdServiceInfo).
     */
    public void tearDown()
    {
        if (mNsdManager != null)
        {
            try
            {
                mNsdManager.unregisterService(mRegistrationListener);
                mNsdManager.stopServiceDiscovery(mDiscoveryListener);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    /**
     * 
     * @return - the DiscoveredDevicesManager that contains all valid devices which have the appropriate service susally will call this
     *         after a msg of RESOLVE_SUCCESS
     */
    public DiscoveredDevicesManager getDeviceManager()
    {
        return deviceManager;
    }

}

最后这是服务器的基础

    @Override
    public void run()
    {
        try
        {
            receiverSocket = new ServerSocket(0);

            onPortObtained(receiverSocket.getLocalPort());

            Log.d(TAG, "run");
            while (broadcastConnection)
            {
                try
                {
                    Socket newConnectionSocket = receiverSocket.accept();
                    onNewConnection(newConnectionSocket.getRemoteSocketAddress(), newConnectionSocket.getLocalSocketAddress());
                                    // to clarify this line launches a function that starts threads to handle the socket.
                    recieveConnection(newConnectionSocket);

                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        catch (IOException e1)
        {
            e1.printStackTrace();
        }
    }

编辑:还有一件事,有时在运行设备时会随机重启。没有常见的事情导致,除此之外他们正在运行应用程序。

1 个答案:

答案 0 :(得分:0)

由于服务发现难以处理,我将通过执行初始ping来构建我自己的发现

        List<DiscoveredDevice> devices = new ArrayList<DiscoveredDevice>();
        for (int i = 0; i < 256; i++)
        {
            // this hardcoded ip will be variable from the wifi's ip
            String ip = "xx.xx.x." + i;
            // this socket may be forever hard coded unless i find a better way. :(
            devices.add(new DiscoveredDevice(32999, ip, "", ""));
        }

点击所有设备,注册接受的每个设备,以及接受注册的每个设备。

休假时,它将调度一个命令从每个设备队列中删除,并且在尝试向设备发送未被接受的连接时,它将被删除。

Hackish,但Android的方式并不适合我:(,这种方式非常有效。