android之同一wifi下两台设备通过UDP进行通讯
16lz
2021-12-04
参考文章地址:http://www.cocoachina.com/android/20171016/20806.html
前端布局如下:
Activity中的全部代码,其中使用了butterknife实现View中控件的实例化。
----------------- 总结: 注意在发送之前,需要先点击开启。 在开启的方法中,红色加粗部分的代码 socket.setUIUpdateListener, 是注册的回调函数(后续解释这个回调函数),在这个函数中执行了接受消息的语句。接受和发送消息,需要使用 DatagramSocket套接字和DatagramPacket数据包组装发送和接收的数据, 因为发送和接受信息会阻塞线程,所以发送和接受的方法需要写在子线程中。 发送端:伪代码 1.首先,创建一个发送的DatagramSocket client = new DatagramSocket(CLIENT_PORT); 2.获取接收端的ip地址 InetAddress local = null; try { // 换成服务器端IP local = InetAddress. getByName (ip); } catch (UnknownHostException e) { e.printStackTrace(); } 3.定义发送信息的字节数组 byte[] messageByte = message.getBytes(); 4.创建DatagramPacket包组装数据,然后发送出去 DatagramPacket p = new DatagramPacket(messageByte, msg_length, local, server_port); try { s.send(p); } catch (IOException e) { e.printStackTrace(); } 接收端: 1.创建一个接收消息的字节数组,并规定数组的长度 byte[] message = new byte[1024]; 2.创建接收的DatagramSocket client = new DatagramSocket(CLIENT_PORT); 3.创建接收数据的DatagramPacket receivePacket = new DatagramPacket(receiveByte, BUFFER_LENGTH); client.receive(receivePacket);
补充:说说回调函数。 参考地址: https://blog.csdn.net/a78270528/article/details/46918601 在UDPSocket类中接收到数据以后,需要把接收的数据显示在界面上,使用的回调函数。 什么是回调函数, 简单来说:回调函数就是预留给系统调用的函数,而且我们往往知道该函数被调用的时机。就好比这个项目中,回调函数是预留给Activity调用的,当接收到信息的时候进行回调,接收到信息进行UI界面更新的过程就叫”回调“。 如下图:
1.在UDPSocket类中定义一个接口(规范) 2.在Activity中注册接口,提前告诉系统这里有UI的方法等待调用,该方法具体实现更新UI。 3.在UDPSocket类中定义方法开启接受信息的方法,收到消息后调用更新UI的接口,告诉系统要调用注册的监听里的方法了。
前端布局如下:
Activity中的全部代码,其中使用了butterknife实现View中控件的实例化。
package com.example.a260219.myapplication;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.annotation.Nullable;import android.support.v7.app.AppCompatActivity;import android.text.TextUtils;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import java.net.DatagramPacket;import butterknife.ButterKnife;import butterknife.InjectView;import butterknife.OnClick;import utils.UDPSocket;public class AndroidUdpNewAcitivity extends AppCompatActivity { @InjectView(R.id.tv_receive_ip) EditText tvReceiveIp; @InjectView(R.id.tv_receive_port) TextView tvReceivePort; @InjectView(R.id.btn_start) Button btnStart; @InjectView(R.id.tv_service_msg) EditText tvServiceMsg; @InjectView(R.id.btn_send) Button btnSend; @InjectView(R.id.btn_reset) Button btnReset; @InjectView(R.id.tv_received_ip) TextView tvReceivedIp; @InjectView(R.id.tv_receive_msg) TextView tvReceiveMsg; private UDPSocket socket; private String rip;//接收端ip private String sip;//服务端ip private int port; private String message; private DatagramPacket receivePacket; int count = 0; public Handler mhandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); receivePacket = (DatagramPacket) msg.obj; String strReceive = new String(receivePacket.getData(), 0, receivePacket.getLength()); tvReceivedIp.setText(receivePacket.getAddress().getHostAddress()); tvReceivePort.setText(receivePacket.getPort() + ""); tvReceiveMsg.setText(strReceive); } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_new_udp); ButterKnife.inject(this); } public void myToast(String str) { Toast.makeText(AndroidUdpNewAcitivity.this, str, Toast.LENGTH_SHORT).show(); } @OnClick({R.id.btn_start, R.id.btn_send,R.id.btn_reset}) public void onClick(View view) { switch (view.getId()) { case R.id.btn_start: if(TextUtils.isEmpty(tvReceiveIp.getText())||TextUtils.isEmpty(tvReceivePort.getText())){ myToast("接收端ip或者port不能为空"); return; } rip=tvReceiveIp.getText().toString(); port=Integer.parseInt(tvReceivePort.getText().toString()); if(socket==null){ socket = new UDPSocket(rip, port, this); } //注册回调函数 socket.setUIUpdateListener(new UDPSocket.UIUpdateListener() { @Override public void upUI(DatagramPacket receivePacket) { Message msg = new Message(); msg.obj = receivePacket; mhandler.sendMessage(msg); } }); break; case R.id.btn_send: if(TextUtils.isEmpty(tvServiceMsg.getText().toString())){ myToast("发送消息不能为空"); return; } message=tvServiceMsg.getText().toString(); ++count;//记录点击发送的次数 socket.sendMessage(message+count); break; case R.id.btn_reset: tvReceivedIp.setText(""); tvReceiveMsg.setText(""); break; } }}
--------------------------- UDPSocket.java中的代码: //接口规范 public interface UIUpdateListener { void upUI(DatagramPacket receivePacket); } public void setUIUpdateListener(UIUpdateListener listener){ startUDPSocket(listener); } public void startUDPSocket(UIUpdateListener listener) { if (client != null) return; try { client = new DatagramSocket(CLIENT_PORT); if (receivePacket == null) { receivePacket = new DatagramPacket(receiveByte, BUFFER_LENGTH); } startSocketThread(listener); } catch (SocketException e) { e.printStackTrace(); } } /** * 接收数据 */ private void startSocketThread(final UIUpdateListener listener) { clientThread = new Thread(new Runnable() { @Override public void run() { Log.d(TAG, "clientThread is running..."); receiveMessage(listener); } }); isThreadRunning = true; clientThread.start(); } /** * 处理接受到的消息 */ private void receiveMessage(UIUpdateListener listener) { while (isThreadRunning) { try { if (client != null) { client.receive(receivePacket); } lastReceiveTime = System.currentTimeMillis(); Log.d(TAG, "receive packet success..."); } catch (IOException e) { Log.e(TAG, "UDP数据包接收失败!线程停止"); stopUDPSocket(); e.printStackTrace(); return; } if (receivePacket == null || receivePacket.getLength() == 0) { Log.e(TAG, "无法接收UDP数据或者接收到的UDP数据为空"); continue; } //解析接收到的 json 信息 // 每次接收完UDP数据后,重置长度。否则可能会导致下次收到数据包被截断。 if (receivePacket != null) { listener.upUI(receivePacket); receivePacket.setLength(BUFFER_LENGTH); } } } public void stopUDPSocket() { isThreadRunning = false; receivePacket = null; if (clientThread != null) { clientThread.interrupt(); } if (client != null) { client.close(); client = null; } if (timer != null) { timer.exit(); }/** * 发送 */public void sendMessage(final String message) { this.BROADCAST_MSG=message; mThreadPool.execute(new Runnable() { @Override public void run() { try { InetAddress targetAddress = InetAddress.getByName(BROADCAST_IP); DatagramPacket packet = new DatagramPacket(message.getBytes(), message.length(), targetAddress, CLIENT_PORT); client.send(packet); // 数据发送事件 Log.d(TAG, "数据发送成功"); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } });} }
----------------- 总结: 注意在发送之前,需要先点击开启。 在开启的方法中,红色加粗部分的代码 socket.setUIUpdateListener, 是注册的回调函数(后续解释这个回调函数),在这个函数中执行了接受消息的语句。接受和发送消息,需要使用 DatagramSocket套接字和DatagramPacket数据包组装发送和接收的数据, 因为发送和接受信息会阻塞线程,所以发送和接受的方法需要写在子线程中。 发送端:伪代码 1.首先,创建一个发送的DatagramSocket client = new DatagramSocket(CLIENT_PORT); 2.获取接收端的ip地址 InetAddress local = null; try { // 换成服务器端IP local = InetAddress. getByName (ip); } catch (UnknownHostException e) { e.printStackTrace(); } 3.定义发送信息的字节数组 byte[] messageByte = message.getBytes(); 4.创建DatagramPacket包组装数据,然后发送出去 DatagramPacket p = new DatagramPacket(messageByte, msg_length, local, server_port); try { s.send(p); } catch (IOException e) { e.printStackTrace(); } 接收端: 1.创建一个接收消息的字节数组,并规定数组的长度 byte[] message = new byte[1024]; 2.创建接收的DatagramSocket client = new DatagramSocket(CLIENT_PORT); 3.创建接收数据的DatagramPacket receivePacket = new DatagramPacket(receiveByte, BUFFER_LENGTH); client.receive(receivePacket);
补充:说说回调函数。 参考地址: https://blog.csdn.net/a78270528/article/details/46918601 在UDPSocket类中接收到数据以后,需要把接收的数据显示在界面上,使用的回调函数。 什么是回调函数, 简单来说:回调函数就是预留给系统调用的函数,而且我们往往知道该函数被调用的时机。就好比这个项目中,回调函数是预留给Activity调用的,当接收到信息的时候进行回调,接收到信息进行UI界面更新的过程就叫”回调“。 如下图:
1.在UDPSocket类中定义一个接口(规范) 2.在Activity中注册接口,提前告诉系统这里有UI的方法等待调用,该方法具体实现更新UI。 3.在UDPSocket类中定义方法开启接受信息的方法,收到消息后调用更新UI的接口,告诉系统要调用注册的监听里的方法了。
更多相关文章
- 箭头函数的基础使用
- Python技巧匿名函数、回调函数和高阶函数
- Android(安卓)Audio延迟(latency)
- android 发送短信的两种方式
- Android(安卓)Intent 常见用法总结
- android中的广播接收器
- android 单例
- android 单例
- 1.5 Android(安卓)入门实例 后台循环发短信