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来建立数据传输.

相关推荐
JavaGuide5 分钟前
JDK 25(长期支持版) 发布,新特性解读!
java·后端
用户3721574261355 分钟前
Java 轻松批量替换 Word 文档文字内容
java
白鲸开源6 分钟前
教你数分钟内创建并运行一个 DolphinScheduler Workflow!
java
weiwenhao17 分钟前
关于 nature 编程语言
人工智能·后端·开源
Java中文社群1 小时前
有点意思!Java8后最有用新特性排行榜!
java·后端·面试
代码匠心1 小时前
从零开始学Flink:数据源
java·大数据·后端·flink
间彧1 小时前
Spring Boot项目中如何自定义线程池
java
间彧1 小时前
Java线程池详解与实战指南
java
用户298698530142 小时前
Java 使用 Spire.PDF 将PDF文档转换为Word格式
java·后端
渣哥2 小时前
ConcurrentHashMap 1.7 vs 1.8:分段锁到 CAS+红黑树的演进与性能差异
java