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