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