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

标签 java android android-wifi

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

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

enter image description here

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

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

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

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

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

这是我的基本音乐分享 Activity 的截图,其中列出了可用的 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;
}

我已经包含了代码以供引用。谢谢。

最佳答案

只需将名称设置并存储在 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 是不合适的。

关于java - 如何像某些文件传输应用程序那样通过 WiFi 发布设备名称(变量)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41163810/

相关文章:

java - 如何使用 Assist API android m

java - 在 Spring Data Repositories 之上使用 EntityManager

android - 从通知启动 Activity

android - 如何从 IP 地址解析网络主机名

android - 如何在 EPOCH 时间获取 android wifi scanresult.timestamp

Android Wi-Fi Direct 在连接前发送数据

java - android系统会阻止FCM通知吗

java - 获取 zip 条目的实际大小

android - java.lang.IllegalArgumentException : Invalid column data1 in onActivityResult()

android - 从 android 帐户管理器 "add account"中删除我的应用程序