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

9
我希望能够通过WiFi发布或广告我的设备名称,该名称是可变的,并且可以由用户更改。
例如,以文件传输应用程序Xender为例。当我们在应用程序中选择“接收”选项时,我们可以在屏幕上看到用户设置的设备名称。这是屏幕截图。

enter image description here

您可以在图像中看到出现了名称shah.kaushal
我在互联网上搜索了许多结果,但无法确定它是什么。我知道主机名,但我认为通常这些应用程序不会更改它,并且我认为它需要在安卓上具有一些特殊的权限才能这样做。因此,我确定它不是主机名,我们可以轻松从IP地址获取主机名。
请注意,我没有复制其他应用程序的功能。我希望在我的音乐播放器应用程序中分享歌曲。
为此,我使用了设备之间的TCP连接。我可以成功地将歌曲从一个设备发送到另一个设备。但是,它需要设备的IP地址。这对用户来说不太友好。
以下是我基本音乐分享活动的屏幕截图,其中列出了可用的IP地址,用户必须从列表中选择一个IP。

enter image description here

在这里,我希望显示设备名称而不是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;
}

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

2个回答

1

只需将名称设置并存储为字符串在SharedPreferences或其他位置,然后当您显示列出IP的屏幕时,连接到它们中的每一个并传输此字符串并显示它,而不是IP。类似于通过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

那么您的意思是我必须连接到每个可用设备以获取“设备名称”字符串,然后才能实际连接它们进行文件传输?我说得对吗? - Kaushal28
在显示接收者列表并发送文件之前,您将连接到getClientList()中的每个IP。 - Steve M
好的,谢谢。我今天会尝试一下并告诉你结果。 - Kaushal28
嘿,非常感谢...你的想法和代码都完美地运行了。授予 +50! - Kaushal28

0
尝试一下这个: 对于每个IP地址,您可以使用InetAddress类解析主机名。
InetAddress addr = InetAddress.getByName("IP-ADDRESS");
String host = addr.getHostName();
Log.i("host:",host);

希望这可以帮到你。如果不行,我可以建议其他方法。

好的,感谢您的关注。但我认为这些主机名不可更改。而且也不够用户友好。例如,它们大多是字母数字混合的。我想要的是设备可更改的名称,就像我们在Play Store上使用的Xender文件传输应用程序一样,可以由用户设置。 - Kaushal28

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接