java之WIFI模块实现文件传输(开源)

AndroidManifest这里要获取到权限,所以要导入:

复制代码
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

主界面:

复制代码
public class MainActivity extends AppCompatActivity {

    private Button startBtton, stopButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //super的意思是继承父类
       super.onCreate(savedInstanceState);
       //初始化xml组件
       setContentView(R.layout.activity_main);
       //初始化按钮组件
       startBtton=findViewById(R.id.bth_start);
       stopButton=findViewById(R.id.bth_stop);

       //当按钮按下去时候的监听器然后进行跳转到别的界面
        startBtton.setOnClickListener(v->startActivity(new Intent(MainActivity.this ,ServerActivity.class)));

        stopButton.setOnClickListener(view ->startActivity(new Intent(MainActivity.this,ClientActivity.class)) );
    }
}

服务器端:

复制代码
public class ServerActivity extends AppCompatActivity {
    private static final String TAG="ServerActivity";
    //mRegistrationListener: 监听NSD服务注册状态的回调接口。
    private NsdManager mNsdManager=null;
    private  NsdManager.RegistrationListener mRegistrationListener;
    //CHAT_PORT: 定义了用于通信的端口号。
    private  final int CHAT_PORT=6613;
    //udpListenerThread: 用于UDP监听的线程。
    private Thread udpListenerThread;
    //running: 用于控制UDP监听线程是否运行的标志。
    private boolean running = false;
    //packet: 用于接收UDP数据包的对象。
    private DatagramPacket packet;
    //BUFFER_SIZE: 定义了缓冲区的大小。
    private final int BUFFER_SIZE = 1024*6;
    private byte[] buffer = new byte[BUFFER_SIZE];
    //serverTV 和 msgTV: 分别是用于显示服务器状态和接收到的消息的TextView控件。
    private TextView serverTV, msgTV;

    //构造方法: 一个空的构造方法。
    public ServerActivity() {
    }


    @SuppressLint("MissingInflatedId")
    @Override
    //onCreate: 活动创建时调用的方法,用于初始化界面和设置NSD服务。
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_server);
        serverTV = findViewById(R.id.tv_server_state);
        msgTV = findViewById(R.id.tv_msg_receive);

        //设置mRegistrationListener的回调方法。
        mRegistrationListener=new NsdManager.RegistrationListener() {
            @SuppressLint("SetTextI18n")
            @Override
            //获取NSD服务管理器,创建NsdServiceInfo对象并注册服务。
            //当服务注册失败时调用。参数serviceInfo包含有关尝试注册的服务的信息,
            // errorCode提供了失败的原因。这里通过调用Log.i记录信息,并使用runOnUiThread更新UI,显示"nsd服务:注册失败"。
            public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
                Log.i(TAG,"onRegistrationFailed ");
                runOnUiThread(() -> serverTV.setText("nsd服务:注册失败"));
            }
                @SuppressLint("SetTextI18n")
                @Override
                // 当服务注销失败时调用。参数含义与上一个方法相同。这里更新UI显示"nsd服务:取消注册失败"。
                public void onUnregistrationFailed (NsdServiceInfo nsdServiceInfo,int i){
                    Log.i(TAG, "onUnregistrationFailed ");
                    runOnUiThread(() -> serverTV.setText("nsd服务:取消注册失败"));
                }
                @SuppressLint("SetTextI18n")
                @Override
                // 当服务成功注册时调用。参数serviceInfo包含已注册服务的详细信息。这里更新UI显示"nsd服务:注册成功"。
                public void onServiceRegistered (NsdServiceInfo nsdServiceInfo){
                    Log.i(TAG, "onServiceRegistered ");
                    runOnUiThread(() -> serverTV.setText("nsd服务:注册成功"));
                }
                @SuppressLint("SetTextI18n")
                @Override
                //当服务成功注销时调用。参数含义与注册成功时相同。这里更新UI显示"nsd服务:取消注册成功"。
                public void onServiceUnregistered (NsdServiceInfo nsdServiceInfo){
                    Log.i(TAG, "onServiceUnregistered ");
                    runOnUiThread(() -> serverTV.setText("nsd服务:取消注册成功"));
                }
            };




        //这行代码通过调用getSystemService方法获取系统服务NSD_SERVICE,即Network Service
        mNsdManager = (NsdManager) getSystemService(NSD_SERVICE);
        //创建了一个NsdServiceInfo对象,这个对象用于存储关于要注册的服务的信息
        NsdServiceInfo serviceInfo = new NsdServiceInfo();
        //设置服务的名称为"test"。这个名称将用于客户端搜索服务时的标识。
        serviceInfo.setServiceName("test");
        //设置服务监听的端口号。CHAT_PORT应该是一个定义好的端口常量,用于聊天服务。
        serviceInfo.setPort(CHAT_PORT);
        //客户端发现服务器是需要对应的这个Type字符串 ;_http._tcp.
        serviceInfo.setServiceType("_saixiang._tcp.");
        //客户端发现服务器是需要对应的这个Type字符串 ;_http._tcp.
        //使用NsdManager的registerService方法注册服务。第一个参数是之前创建的serviceInfo对象,
        // 第二个参数指定使用的协议为DNS-SD,第三个参数是一个监听器mRegistrationListener,用于接收服务注册过程中的状态更新。
        mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
        //这行代码被注释掉了,如果取消注释,它将启动一个UDP监听器。UDP是一种无连接的网络协议,常用于需要快速传输但可以容忍一些数据丢失的场景。
        //startUdpListener();
        //这行代码调用了一个名为startListen的方法,这个方法的具体实现没有给出,但它的目的可能是启动一个监听器来处理网络请求。
        startListen();
    }





    private boolean ifListen=true;
    private ServerSocket serverSocket = null;
    private Socket socket = null;
    boolean ifSocketThreadStart = false;

    /*开始监听
   * */
   //线程定义: socketThread是一个内部线程类,用于处理TCP连接和数据接收。
    private final Thread socketThread = new Thread() {
        //这是线程的run方法,当线程启动时候会执行这个方法
        public void run() {
            //无限循环,表示线程会一直运行直到程序终止
            while (true) {
                try {
                    //这个条件判断如果serverSocket是null并且ifListen为true,则执行大括号里的代码
                    if (serverSocket == null && ifListen) {
                        //定义了一个端口为6613的变量
                        int socket_port = 6613;
                        //创建一个新的serverSocket对象,监听6613端口
                        serverSocket = new ServerSocket(socket_port);
                        //如果serverSocket不是null,则执行大括号里的代码
                    } else if (serverSocket != null) {
                        //调用Accept方法等待客户端连接,并将连接的Socket对象赋值给变量socket
                        socket = serverSocket.accept();
                        if (socket != null) {
                            //创建一个包装了socket输入流的BufferedInputStream,再包装成DataInputStream,用于高效读取数据。
                            DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
                            try {

                                //定义了一个大小为1024的字节数组,用作数据缓冲区
                                byte[] buffer = new byte[1024];
                                int len = 0;
                                //这是一个循环,当从DataInputStream读取到数据(len不为-1)时候,执行大括号里的代码
                                while ((len = in.read(buffer)) != -1) {
                                    //使用读取到的数据和"GB2312"编码创建一个字符串。
                                    String text = new String(buffer, 0, len, "GB2312");
                                    //打印日志,记录接收到的数据。
                                    Log.d("test", "收到的数据为:" + text);
                                }
                               // 捕获并处理DataInputStream读取过程中可能发生的异常。
                            } catch (Exception e) {
                                Log.d("test", "DataService read: " + e);
                                //调用一个自定义的方法来销毁socket,可能是关闭连接。
                                destroySocket();
                            }
                        }
                    }
                    //捕获并处理ServerSocket创建或accept方法调用过程中可能发生的异常。
                } catch (IOException e1) {
                    Log.d("test", "DataService accept: " + e1);
                    destroySocket(); }
            }
        }
    };

    //startListen 用于启动
    public void startListen() {
        ifListen = true;
        if (!ifSocketThreadStart) {
            ifSocketThreadStart = true;
            socketThread.start();
        }
    }
    //停止TCP监听stopListen:
    public void stopListen() {
        ifListen = false;
        destroySocket();
    }
    //用于关闭和重置ServerSocket和Socket。
    private void destroySocket() {
        //开始一个 try 块,用于捕获并处理可能发生的异常。
        try {
            //检查 serverSocket 是否不为 null 且没有被关闭。
            if (serverSocket != null && !serverSocket.isClosed()) {
                //如果条件满足,调用 close 方法关闭 serverSocket。
                serverSocket.close();
            }
            //如果关闭 serverSocket 时发生 IOException,将进入这个 catch 块。
        } catch (IOException e) {
//            AppLog.Log(e.toString());
        }
        //无论是否发生异常,都会执行 finally 块中的代码。
        finally {
          //将 serverSocket 设置为 null,以确保它不再被使用。
            serverSocket = null;
        }
        //开始另一个 try 块,用于关闭另一个套接字 socket。
        try {
            //检查 socket 是否不为 null 且没有被关闭。
            if (socket != null && !socket.isClosed()) {
                //如果条件满足,调用 close 方法关闭 socket。
                socket.close();
            }
        }//如果关闭 socket 时发生 IOException,将进入这个 catch 块。
        catch (IOException e) {
//            AppLog.Log(e.toString());
        }
        //无论是否发生异常,都会执行 finally 块中的代码。
        finally {
            //将 socket 设置为 null,以确保它不再被使用。
            socket = null;
        }
    }


    @Override
    //onDestroy: 活动销毁时调用的方法,用于注销NSD服务和停止监听。
    protected void onDestroy() {
        //这是调用父类(即Activity类)的onDestroy()方法,以确保父类中的资源得到正确释放。
        super.onDestroy();
        //: 这个方法用于停止NSD服务。NSD服务允许应用程序在本地网络中注册和发现服务。
         stopNSDServer();
//       stopUdpListener();
         destroySocket();
         stopListen();
    }
    //NSD服务注册与注销: 通过mNsdManager注册和注销服务,以便其他设备可以通过NSD发现此服务
    public void stopNSDServer() {
        // mRegistrationListener作为参数传递,这样当服务取消注册时,监听器会收到相应的回调。
        mNsdManager.unregisterService(mRegistrationListener);
    }
}

截取了soket应该怎么接收和建立传输数据.

客户端:

复制代码
//ClientActivity 继承自 AppCompatActivity表明它是一个可以处理配置更改(如屏幕旋转)的活动。
public class ClientActivity extends AppCompatActivity {
    private static final String TAG = "ClientActivity";
    private RecyclerView recyclerView;
    private NsdManager mNsdManager = null;
    //mNsdManager: 用于网络服务发现的 NsdManager 实例。
    private NsdManager.DiscoveryListener mNSDDiscoveryListener = null;    //    搜寻监听器
    private NsdManager.ResolveListener mNSDResolveListener = null;//    解析监听器
    private NSDDeviceAdapter adapter;
    private TextView serverTV;




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //设置了活动的布局
        setContentView(R.layout.activity_client);
        serverTV=findViewById(R.id.tv_server_state_s);
        //获取了布局中RecyclerView组件
        recyclerView = findViewById(R.id.recyclerView);
        //为RecyclerView设置了线性布局管理器
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        //创建了一个适配器,用于管理RecyclerView中显示的数据
        adapter = new NSDDeviceAdapter();
        //将适配器设置到recyclerView上
        recyclerView.setAdapter(adapter);
        //服务发现监听器 (mNSDDiscoveryListener):定义了多个回调方法,用于处理服务发现过程中的不同事件。
        mNSDDiscoveryListener = new NsdManager.DiscoveryListener() {
            @Override
            //在开始服务时调用。
            public void onStartDiscoveryFailed(String serviceType, int errorCode) {
                Log.i(TAG,"onStartDiscoveryFailed ");
            }
            // 停止服务发现失败时调用
            @Override
            public void onStopDiscoveryFailed(String serviceType, int errorCode) {
                //使用 Log.i(TAG, message) 记录信息,其中 message 是要记录的消息
                Log.i(TAG,"onStopDiscoveryFailed ");

            }
           //分别在服务发现开始时调用。
            @Override
            public void onDiscoveryStarted(String serviceType) {
                Log.i(TAG,"onDiscoveryStarted ");

            }
            //分别在服务发现停止时调用。
            @Override
            public void onDiscoveryStopped(String serviceType) {
                Log.i(TAG,"onDiscoveryStopped ");

            }
           //当发现新服务时调用,并使用 mNSDResolveListener 解析服务信息。
            @Override
            public void onServiceFound(NsdServiceInfo serviceInfo) {
                Log.i(TAG,"onServiceFound "+serviceInfo.toString());
                mNsdManager.resolveService(serviceInfo, mNSDResolveListener);
            }
            //当服务不再可用时调用,并从适配器中移除该服务。
            @Override
            public void onServiceLost(final NsdServiceInfo serviceInfo) {
                Log.i(TAG,"onServiceLost ");
                //使用 runOnUiThread(Runnable) 确保在主线程上更新UI,这是Android中更新UI的标准做法
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        adapter.removeDevice(serviceInfo);
                    }
                });
            }
        };

       //用于监听服务解析的结果。
        mNSDResolveListener = new NsdManager.ResolveListener() {
            @Override
            //onResolveFailed: 在服务解析失败时调用。
            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
                Log.i(TAG,"onResolveFailed ");

            }

            @Override
            //onServiceResolved: 在服务解析成功时调用,并更新适配器以添加服务信息
            public void onServiceResolved(final NsdServiceInfo serviceInfo) {
                Log.i(TAG,"onServiceResolved ");
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        adapter.addDevice(serviceInfo);
                    }
                });
            }
        };
        //使用 mNsdManager方法开始服务发现,指定服务类型 _saixiang._tcp.
        mNsdManager = (NsdManager) getSystemService(NSD_SERVICE);
        //使用discoverServices 方法开始服务发现,使用的协议 NsdManager.PROTOCOL_DNS_SD。
        mNsdManager.discoverServices("_saixiang._tcp.", NsdManager.PROTOCOL_DNS_SD, mNSDDiscoveryListener);

        // 客户端在服务解析成功后,尝试与服务器建立连接
        mNSDResolveListener = new NsdManager.ResolveListener() {
            @Override
            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
                // 处理解析失败的情况
                Log.i(TAG,"onResolveFailed ");
            }

            @Override
            public void onServiceResolved(NsdServiceInfo serviceInfo) {
                // 服务解析成功,尝试建立连接
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            // 创建Socket连接
                            Socket socket = new Socket(serviceInfo.getHost(), serviceInfo.getPort());
                            // 发送数据
                            OutputStream out = socket.getOutputStream();
                            out.write("Hello Server!".getBytes());
                            out.flush();
                            // 接收数据
                            InputStream in = socket.getInputStream();
                            byte[] buffer = new byte[1024];
                            int len = in.read(buffer);
                            String received = new String(buffer, 0, len);
                            Log.i(TAG, "Received: " + received);

                            // 关闭连接
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        };
    }

    @Override
    //在活动销毁时停止服务发现,避免资源泄露。
    protected void onDestroy() {
        super.onDestroy();
        mNsdManager.stopServiceDiscovery(mNSDDiscoveryListener);
    }

}

也是建立了socket来建立数据传输.

相关推荐
zjw_rp13 分钟前
Spring-AOP
java·后端·spring·spring-aop
忆源14 分钟前
3.3.2.3 开源项目有锁队列实现--魔兽世界tinityCore
开源
鹏大师运维23 分钟前
聊聊开源的虚拟化平台--PVE
linux·开源·虚拟化·虚拟机·pve·存储·nfs
Oneforlove_twoforjob25 分钟前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言
TodoCoder33 分钟前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
engchina42 分钟前
如何在 Python 中忽略烦人的警告?
开发语言·人工智能·python
向宇it42 分钟前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
小蜗牛慢慢爬行44 分钟前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
诚丞成1 小时前
计算世界之安生:C++继承的文水和智慧(上)
开发语言·c++
Smile灬凉城6661 小时前
反序列化为啥可以利用加号绕过php正则匹配
开发语言·php