如何像某些文件传输应用程序那样通过 WiFi 发布设备名称(变量)?

How to publish device name (Variable) over WiFi, as some File transfer applications do?

我想通过 WiFi 发布或宣传我的设备名称,该名称是可变的,可以由用户更改。

例如,以文件传输应用程序为例Xender。当我们在应用程序中 select receive 选项时,我们可以在屏幕上看到用户设置的设备名称。这是屏幕截图。

您可以在图像中看到名字 shah.kaushal 出现了。

我在 Internet 上搜索了很多结果,但无法弄清楚它到底是什么。

我知道主机名,但我认为通常此类应用程序不会更改它,我认为它需要 android 上的一些特殊权限才能这样做。所以我确定它不是主机名,我们可以从 IP 地址轻松获得它。

请注意,我没有复制任何其他应用程序功能。我希望在我的音乐播放器应用程序中共享歌曲。

为此,我在设备之间使用了 TCP 连接。而且我可以成功地将歌曲从一台设备发送到另一台设备。但它需要设备的 IP 地址。这不是用户友好的。

这是我的基本音乐分享 activity 的屏幕截图,其中列出了可用的 IP 地址,用户必须 select 从列表中选择一个 IP。

这里我想显示设备名称而不是 IP 地址。

我发送文件的代码是:

 @Override
protected Void doInBackground(Void... voids) {


    System.out.println("array list");
    ArrayList<File> files = new ArrayList<>();
    System.out.println("about to create.");

    files.add(new File(wholePath));
    System.out.println("file created..");
    try {


        //Receiving IP addresses which are available to send our files(Music)!!
        a = getClientList();


        //update the UI to display the received IP addresses!!
        publishProgress();


        //busy waiting for user to select appropriate IP address to send files!
        while (destinationAddress.equals("-1")){

        }

        //User has selected something, It's time to send files there!
        socket = new Socket(destinationAddress,5004);

        System.out.println("Connecting...");
        DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
        System.out.println(files.size());
        //write the number of files to the server
        dos.writeInt(files.size());
        dos.flush();


        //write file size
        for(int i = 0;i< files.size();i++){
            int file_size = Integer.parseInt(String.valueOf(files.get(i).length()));
            dos.writeLong(file_size);
            dos.flush();
        }

        //write file names
        for(int i = 0 ; i < files.size();i++){
            dos.writeUTF(files.get(i).getName());
            dos.flush();
        }

        //buffer for file writing, to declare inside or outside loop?
        int n = 0;
        byte[]buf = new byte[4092];
        //outer loop, executes one for each file
        for(int i =0; i < files.size(); i++){

            System.out.println(files.get(i).getName());
            //create new fileinputstream for each file
            FileInputStream fis = new FileInputStream(files.get(i));

            //write file to dos
            while((n =fis.read(buf)) != -1){
                dos.write(buf,0,n);
                dos.flush();

            }

        }

        dos.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        xceptionFlag = true;
        e.printStackTrace();
    }

    Log.i("===end of start ====", "==");
    try{
        if(!socket.isClosed()){
            socket.close();
        }
    }
    catch (Exception e){
        xceptionFlag = true;
        e.printStackTrace();
    }

    return null;
}

接收文件的代码是:

    @Override
protected Void doInBackground(Void... voids) {


    try {


        //this is done isntead of above line because it was givind error of address is already in use.
        ss = new ServerSocket();
        ss.setReuseAddress(true);
        ss.bind(new InetSocketAddress(5004));

        System.out.println("waiting");

        Socket socket = ss.accept();
        System.out.println("Accepted!");
        DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
        //read the number of files from the client
        int number = dis.readInt();
        ArrayList<File>files = new ArrayList<File>(number);
        System.out.println("Number of Files to be received: " +number);

        ArrayList<Long> fileSize = new ArrayList<>(number);


        for(int i = 0; i < number ;i++){
            long size = dis.readLong();
            System.out.println(size);
            fileSize.add(size);
        }

        //read file names, add files to arraylist
        for(int i = 0; i< number;i++){
            File file = new File(dis.readUTF());
            files.add(file);
        }
        int n = 0;
        byte[]buf = new byte[4092];

        //outer loop, executes one for each file
        for(int i = 0; i < files.size();i++){

            System.out.println("Receiving file: " + files.get(i).getName());

            //Create new Folder for our app, if it is not there and store received files there in our separate folder.
            File folder = new File(Environment.getExternalStorageDirectory() +
                    File.separator + "File");
            boolean success = true;
            if (!folder.exists()) {
                success = folder.mkdirs();
            }
            if (success) {
                // Do something on success
            } else {
                // Do something else on failure
            }


            //create a new fileoutputstream for each new file
            FileOutputStream fos = new FileOutputStream("mnt/sdcard/File/" +files.get(i).getName());
            //read file

            while (fileSize.get(i) > 0 && (n = dis.read(buf, 0, (int)Math.min(buf.length, fileSize.get(i)))) != -1)
            {
                fos.write(buf,0,n);
                long x = fileSize.get(i);
                x = x-n;
                fileSize.set(i,x);
            }
            fos.close();
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        xceptionFlag = true;
        e.printStackTrace();

    }
    ////////////////////
    Log.i("== the end of read ====", "==");
    try{
        if(!ss.isClosed()){
            ss.close();
        }
    }
    catch (Exception e){
        xceptionFlag = true;
        e.printStackTrace();
    }
    return null;
}

我已经包含了代码以供参考。谢谢。

试试这个: 对于每个 IP 地址,您可以使用 InetAddress class

解析主机名
InetAddress addr = InetAddress.getByName("IP-ADDRESS");
String host = addr.getHostName();
Log.i("host:",host);

希望这对您有所帮助。如果没有,我可以建议一些其他方法。

只需将名称设置并存储在 SharedPreferences 或任何地方作为字符串,然后当您显示列出 IP 的屏幕时,连接到它们中的每一个并传输此字符串并显示它而不是IP。像 Send a string instead of byte through socket in Java 这样的东西来传输字符串。

当你想从设备发布名字时启动这个服务,当它不应该再发布名字时停止它:

public class NameService extends Service {

    private volatile boolean running;
    private volatile String myName;
    private volatile ServerSocket serverSocket;

    public NameService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        try {
            serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress(5006));
            serverSocket.setReuseAddress(true);
            serverSocket.setSoTimeout(2000);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        myName = PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
                .getString("NAME_STRING", "TEST.NAME");
        if (!running)
        {
            running = true;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (running)
                    {
                        try {
                            Socket socket = serverSocket.accept();
                            PrintWriter writer = new PrintWriter(new BufferedWriter(
                                    new OutputStreamWriter(socket.getOutputStream())),
                                    true);
                            writer.println(myName);

                            writer.close();
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                    }
                }
            }).start();
        }
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        running = false;
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

然后当想要显示接收器列表时,连接到每个接收器并执行以下操作:

try {
        Socket socket = new Socket();
        socket.connect(new InetSocketAddress(ipAddress, 5006), 5000);
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String message = reader.readLine();
        reader.close();
        socket.close();
        Log.i("TAG", message);
        } catch (IOException e) {
        e.printStackTrace();
     }

如果您想在 运行 时更改名称,您可以进一步调用 startService()

我建议您使用 ServiceIntentService 进行文件传输,AsyncTask 不合适。