android udp封装,Android 基于UDP的Socket通信

本文介绍了Android客户端通过UDP协议与PC服务端进行通信的流程,包括建立连接、发送和接收数据、异常处理、心跳包监控及连接状态判断等。在实现过程中,需要注意避免主线程执行网络操作,使用异步线程,并且客户端必须先发送一次数据才能开始接收。此外,还提供了一个简单的UDP客户端类`UdpClient`的代码示例,该类包含了连接、发送、接收和断开连接的方法,并实现了数据接收监听。
摘要由CSDN通过智能技术生成

截图1、Android 客户端

AAffA0nNPuCLAAAAAElFTkSuQmCC

client.png2、PC服务端:用的是SocketTool软件模拟

AAffA0nNPuCLAAAAAElFTkSuQmCC

server.png

流程

1、连接DatagramSocket的服务端(ip和port):开启异步线程和socket

2、发送数据(DatagramPacket):异步

3、接收数据(DatagramPacket):注意连接状态,异步读取

4、关闭连接:关闭DatagramSocket和对应线程

注意

1、异常:android.os.NetworkOnMainThreadException。 socket需要在线程中使用

2、前后端统一传输或者接收协议 [requestcode   size  d1 d2 d3 ... ],在解析时候用得到

3、实施监控socket的连接状态,还是用心跳包发过去,然后返回数据,一段时间没有的话则代表socket连接失败。

4、注意receive接收数据后的有效长度(一个是预存的buffer,一个是有效结果buffer)

5、客户端连上去后不知道为何一定要先发送一次,才能接收?

6、UDP不安全,有长度限制64K

代码1、UdpClient.java:udp-socket的客户端,略微做了通用封装,主要是连接,发送,接收,然后设置监听/**

* Created by wujn on 2019/2/15.

* Version : v1.0

* Function: udp client 64k限制

*/public class UdpClient {    /**

* single instance UdpClient

* */

private static UdpClient mSocketClient = null;    private UdpClient(){}    public static UdpClient getInstance(){        if(mSocketClient == null){            synchronized (UdpClient.class) {

mSocketClient = new UdpClient();

}

}        return mSocketClient;

}

String TAG_log = "Socket";    private DatagramSocket mSocket;    private DatagramPacket sendPacket;    //发送

private DatagramPacket receivePacket; //接受//  private OutputStream mOutputStream;//  private InputStream mInputStream;

private SocketThread mSocketThread;    private boolean isStop = false;//thread flag

/**

* 128 - 数据按照最长接收,一次性

* */

private class SocketThread extends Thread {        private String ip;        private int port;        public SocketThread(String ip, int port){            this.ip = ip;            this.port = port;

}        @Override

public void run() {

Log.d(TAG_log,"SocketThread start ");            super.run();            //connect ...

try {                if (mSocket != null) {

mSocket.close();

mSocket = null;

}

InetAddress ipAddress = InetAddress.getByName(ip);

mSocket = new DatagramSocket();

mSocket.connect(ipAddress, port); //连接

//设置timeout

//mSocket.setSoTimeout(3000);

Log.d(TAG_log,"udp connect = "+isConnect());                if(isConnect()){

isStop = false;

uiHandler.sendEmptyMessage(1);

}                /* 此处这样做没什么意义不大,真正的socket未连接还是靠心跳发送,等待服务端回应比较好,一段时间内未回应,则socket未连接成功 */

else{

uiHandler.sendEmptyMessage(-1);

Log.e(TAG_log,"SocketThread connect fail");                    return;

}

}            catch (IOException e) {

uiHandler.sendEmptyMessage(-1);

Log.e(TAG_log,"SocketThread connect io exception = "+e.getMessage());

e.printStackTrace();                return;

}

Log.d(TAG_log,"SocketThread connect over ");            //发送一次,否则不发送则收不到,不知道为啥。。。

sendByteCmd(new byte[]{00},-1);//send once

//read ...

while (isConnect() && !isStop && !isInterrupted()) {                int size;                try {                    byte[] preBuffer = new byte[4 * 1024];//预存buffer

receivePacket = new DatagramPacket(preBuffer, preBuffer.length);

mSocket.receive(receivePacket);                    if (receivePacket.getData() == null) return;

size = receivePacket.getLength();     //此为获取后的有效长度,一次最多读64k,预存小的话可能分包

Log.d(TAG_log, "pre data size = "+receivePacket.getData().length + ", value data size = "+size);                    byte[] dataBuffer = Arrays.copyOf(preBuffer, size);                    if (size > 0) {

Message msg = new Message();

msg.what = 100;

Bundle bundle = new Bundle();

bundle.putByteArray("data",dataBuffer);

bundle.putInt("size",size);

bundle.putInt("requestCode",requestCode);

msg.setData(bundle);

uiHandler.sendMessage(msg);

}

Log.i(TAG_log, "SocketThread read listening");                    //Thread.sleep(100);//log eof

}                catch (IOException e) {

uiHandler.sendEmptyMessage(-1);

Log.e(TAG_log,"SocketThread read io exception = "+e.getMessage());

e.printStackTrace();                    return;

}

}

}

}    //==============================socket connect============================

private String ip;    private int port;    /**

* connect socket in thread

* Exception : android.os.NetworkOnMainThreadException

* */

public void connect(String ip, int port){        this.ip = ip;        this.port = port;

mSocketThread = new SocketThread(ip, port);

mSocketThread.start();

}    /**

* socket is connect

* */

public boolean isConnect(){        boolean flag = false;        if (mSocket != null) {

flag = mSocket.isConnected();

}        return flag;

}

/**

* socket disconnect

* */

public void disconnect() {

isStop = true;        if (mSocket != null) {

mSocket.close();

mSocket = null;

}        if (mSocketThread != null) {

mSocketThread.interrupt();//not intime destory thread,so need a flag

}

}    /**

* send byte[] cmd

* Exception : android.os.NetworkOnMainThreadException

* */

public void sendByteCmd(final byte[] mBuffer,int requestCode) {        this.requestCode = requestCode;        new Thread(new Runnable() {            @Override

public void run() {                try {

InetAddress ipAddress = InetAddress.getByName(ip);

sendPacket = new DatagramPacket(mBuffer, mBuffer.length, ipAddress, port);

mSocket.send(sendPacket);

} catch (IOException e) {

e.printStackTrace();

}

}

}).start();

}

Handler uiHandler = new Handler() {        @Override

public void handleMessage(Message msg) {            super.handleMessage(msg);            switch(msg.what){                //connect error

case -1:                    if (null != onDataReceiveListener) {

onDataReceiveListener.onConnectFail();

disconnect();

}                    break;                //connect success

case 1:                    if (null != onDataReceiveListener) {

onDataReceiveListener.onConnectSuccess();

}                    break;                //receive data

case 100:

Bundle bundle = msg.getData();                    byte[] buffer = bundle.getByteArray("data");                    int size = bundle.getInt("size");                    int mequestCode = bundle.getInt("requestCode");                    if (null != onDataReceiveListener) {

onDataReceiveListener.onDataReceive(buffer, size, mequestCode);

}                    break;

}

}

};

/**

* socket response data listener

* */

private OnDataReceiveListener onDataReceiveListener = null;    private int requestCode = -1;    public interface OnDataReceiveListener {        public void onConnectSuccess();        public void onConnectFail();        public void onDataReceive(byte[] buffer, int size, int requestCode);

}    public void setOnDataReceiveListener(

OnDataReceiveListener dataReceiveListener) {

onDataReceiveListener = dataReceiveListener;

}

}MainActivity.java:使用,简单明了private void initListener(){        //socket connect

btn_connect.setOnClickListener(new View.OnClickListener() {            @Override

public void onClick(View v) {

String ip = et_ip.getText().toString();

String port = et_port.getText().toString();                if(TextUtils.isEmpty(ip)){

Toast.makeText(UdpActivity.this,"IP地址为空",Toast.LENGTH_SHORT).show();                    return;

}                if(TextUtils.isEmpty(port)){

Toast.makeText(UdpActivity.this,"端口号为空",Toast.LENGTH_SHORT).show();                    return;

}

connect(ip, Integer.parseInt(port));

}

});        //socket disconnect

btn_disconnect.setOnClickListener(new View.OnClickListener() {            @Override

public void onClick(View v) {

disconnect();

}

});        //socket send

btn_send.setOnClickListener(new View.OnClickListener() {            @Override

public void onClick(View v) {                if (UdpClient.getInstance().isConnect()) {                    byte[] data = et_send.getText().toString().getBytes();

send(data);

} else {

Toast.makeText(UdpActivity.this,"尚未连接,请连接Socket",Toast.LENGTH_SHORT).show();

}

}

});        //clear receive

btn_clear.setOnClickListener(new View.OnClickListener() {            @Override

public void onClick(View v) {

tv_receive.setText("");

}

});

}    /**

* socket data receive

* */

private void initDataReceiver(){

UdpClient.getInstance().setOnDataReceiveListener(dataReceiveListener);

}    /**

* socket connect

* */

private void connect(String ip, int port){

UdpClient.getInstance().connect(ip, port);

}    /**

* socket disconnect

* */

private void disconnect(){

UdpClient.getInstance().disconnect();

tv_state.setText("未连接");

}    /**

* socket send

* */

private void send(byte[] data){

String ip = et_ip.getText().toString();

String port = et_port.getText().toString();

UdpClient.getInstance().sendByteCmd(data,1001);

}    /**

* socket data receive

* data(byte[]) analyze

* */

private UdpClient.OnDataReceiveListener dataReceiveListener = new UdpClient.OnDataReceiveListener() {        @Override

public void onConnectSuccess() {

Log.i(TAG_log,"onDataReceive connect success");

tv_state.setText("已连接");

}        @Override

public void onConnectFail() {

Log.e(TAG_log,"onDataReceive connect fail");

tv_state.setText("未连接");

}        @Override

public void onDataReceive(byte[] buffer, int size, int requestCode) {            //获取有效长度的数据

byte[] data = new byte[size];

System.arraycopy(buffer, 0, data, 0, size);            final String oxValue = Arrays.toString(HexUtil.Byte2Ox(data));

Log.i(TAG_log,"onDataReceive requestCode = "+requestCode + ", content = "+oxValue);

tv_receive.setText(tv_receive.getText().toString() + oxValue + "\n");

}

};    @Override

protected void onDestroy() {

UdpClient.getInstance().disconnect();        super.onDestroy();

}

作者:Kandy_JS

链接:https://www.jianshu.com/p/9dbb8ac146f6

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值