Android实现Udp socket通信且对数据进行分包和解析

Udp socket通信和Tcp socket通信原理,请参考:
《Android中关于Socket通信数据大小,内存缓冲区和数据可靠性的一点调查》

核心代码

初始化UDP socket和接收Packet:

mUdpSocket = new DatagramSocket(UDP_SOCKET_PORT);
mRecvPacket = new DatagramPacket(mReceiveByte, PACKAGE_BUFFER_SIZE);

数据发送和分包:

synchronized(mLock) {
	InetAddress targetAddress = InetAddress.getByName(UDP_SOCKET_HOST);
	for( int i = 0; i < packageNum; i++ ){
	    if(i == packageNum - 1 ){
	        mSendBuffer.dataBuf = new byte[(size + 8) - i * PACKAGE_BUFFER_SIZE];
	        System.arraycopy(buffer, i * PACKAGE_BUFFER_SIZE, mSendBuffer.dataBuf, 0, (size + 8) - i * PACKAGE_BUFFER_SIZE);
	    }else{
	        mSendBuffer.dataBuf = new byte[PACKAGE_BUFFER_SIZE];
	        System.arraycopy(buffer, i * PACKAGE_BUFFER_SIZE, mSendBuffer.dataBuf, 0, PACKAGE_BUFFER_SIZE);
	    }
	    Log.i(TAG,"sendDataToDashboard,write.size()=" + mSendBuffer.dataBuf.length);
	    DatagramPacket packet = new DatagramPacket(mSendBuffer.dataBuf, mSendBuffer.dataBuf.length, targetAddress, UDP_SOCKET_PORT);
	    mUdpSocket.send(packet);
	}
}

数据接收和解析:
readData()

完整代码实现:

public class AndroidUdpSocketService extends Service {
    private static final String TAG = AndroidUdpSocketService.class.getName();
    private static DatagramSocket mUdpSocket;
    private static DatagramPacket mRecvPacket;
    private static BackgroundExecutor mBackgroundExecutor;
    private byte[] mReceiveByte = new byte[PACKAGE_BUFFER_SIZE];
    private boolean isAndroidUdpSocketLive = false;
    private static final String UDP_SOCKET_HOST= "255.255.255.255";
    private static final int UDP_SOCKET_PORT= 6002;
    private static final int READ_BUFFER_LENGTH = 1024;
    private static final Object mLock = new Object();

    private static final int PACKAGE_BUFFER_SIZE = 50000;
    class SocketDataBuffer
    {
        byte[] dataBuf;
        int flag;   // 0,middle data; 1,the last data

    };
    static SocketDataBuffer mSendBuffer;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG,"onCreate");
        mBackgroundExecutor = BackgroundExecutor.get();
        mSendBuffer = new SocketDataBuffer();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG,"onStartCommand");
        createNotificationChannel();
        new InitUdpSocketThread().start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG,"onDestroy");
        releaseLastSocket();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        Log.i(TAG,"onLowMemory");
    }

    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
        Log.i(TAG,"onTrimMemory");
    }

    private void createNotificationChannel() {
        NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        String id = "car_launcher_02";
        CharSequence name = "AndroidUdpSocketService";
        String description = "Udp Socket Service";
        NotificationChannel mChannel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_MIN);
        mChannel.setDescription(description);
        mChannel.setSound(null, null);
        mNotificationManager.createNotificationChannel(mChannel);
        Notification notification = new Notification.Builder(this)
                .setChannelId(id)
                .setSmallIcon(R.drawable.ic_home)
                .build();
        startForeground(12,notification);
    }

    class InitUdpSocketThread extends Thread {
        @Override
        public void run() {
            super.run();
            try {
                Log.i(TAG,"InitSocketThread,new socket");
                //Start Heartbeat
                //mHandler.postDelayed(mHeartbeatRunnable, HEART_BEAT_RATE);

                //Create tcp socket connect
                mUdpSocket = new DatagramSocket(UDP_SOCKET_PORT);
                mRecvPacket = new DatagramPacket(mReceiveByte, PACKAGE_BUFFER_SIZE);
                mUdpSocket.setSendBufferSize(1024*1024*10);
                mUdpSocket.setReceiveBufferSize(1024*1024*10);

                Log.i(TAG,"new Socket,mUdpSocket.getSendBufferSize()=" + mUdpSocket.getSendBufferSize());
                Log.i(TAG,"new Socket,mUdpSocket.getReceiveBufferSize()=" + mUdpSocket.getReceiveBufferSize());
                isAndroidUdpSocketLive = true;
                readDataFromDashboard();
            } catch (IOException e) {
                //e.printStackTrace();
                Log.i(TAG,"new Socket,IOException" + e.getMessage());
            }
        }
    }

    private void releaseLastSocket() {
        isAndroidUdpSocketLive = false;

        Log.i(TAG,"releaseLastSocket2");
        if (null != mUdpSocket) {
            Log.i(TAG,"releaseLastSocket2,mSocket.isClosed()=" + mUdpSocket.isClosed());
            mUdpSocket.close();
            mUdpSocket = null;
        }
    }

    public static boolean sendData(final int frameType,final int frameID,final byte[] data) {
//        Log.i(TAG,"sendData,mUdpSocket != null," + (mUdpSocket != null));
//        Log.i(TAG,"sendData,mUdpSocket.isClosed()," + (mUdpSocket.isClosed()));
//        Log.i(TAG,"sendData,mUdpSocket.isConnected()," + (mUdpSocket.isConnected()));
        if( mUdpSocket != null && !mUdpSocket.isClosed()) {
            mBackgroundExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    //do something
                    Log.i(TAG, "sendData,start");
                    int size = data.length;
                    byte buffer[] = new byte[8 + size];
                    buffer[0] = (byte) 0xA6;
                    buffer[1] = 0x6A;
                    buffer[2] = (byte) frameType;
                    buffer[3] = (byte) ((size & 0xff000000) >> 24);
                    buffer[4] = (byte) ((size & 0x00ff0000) >> 16);
                    buffer[5] = (byte) ((size & 0x0000ff00) >> 8);
                    buffer[6] = (byte) ((size & 0x000000ff));
                    buffer[7] = (byte) frameID;

                    System.arraycopy(data, 0, buffer, 8, size);
                    Log.i(TAG, "sunxiaolin,sendData,size=" + size);
                    //Log.i(TAG, "sendData,data=" + data);
                    //Log.i(TAG, "sendData,buffer=" + Utils.printHexBinary(buffer));
                    int packageNum = (size + 8) / PACKAGE_BUFFER_SIZE + 1 ;
                    Log.i(TAG, "sendDataTo,packageNum=" + packageNum);
                    try {
                        synchronized(mLock) {
                            InetAddress targetAddress = InetAddress.getByName(UDP_SOCKET_HOST);
                            for( int i = 0; i < packageNum; i++ ){
                                if(i == packageNum - 1 ){
                                    mSendBuffer.dataBuf = new byte[(size + 8) - i * PACKAGE_BUFFER_SIZE];
                                    System.arraycopy(buffer, i * PACKAGE_BUFFER_SIZE, mSendBuffer.dataBuf, 0, (size + 8) - i * PACKAGE_BUFFER_SIZE);
                                }else{
                                    mSendBuffer.dataBuf = new byte[PACKAGE_BUFFER_SIZE];
                                    System.arraycopy(buffer, i * PACKAGE_BUFFER_SIZE, mSendBuffer.dataBuf, 0, PACKAGE_BUFFER_SIZE);
                                }
                                Log.i(TAG,"sendData,write.size()=" + mSendBuffer.dataBuf.length);
                                DatagramPacket packet = new DatagramPacket(mSendBuffer.dataBuf, mSendBuffer.dataBuf.length, targetAddress, UDP_SOCKET_PORT);
                                mUdpSocket.send(packet);
                            }
                        }
                        Log.i(TAG, "sunxiaolin,sendData,write success.");
                    } catch (IOException e) {
                        //e.printStackTrace();
                        Log.i(TAG, "sunxiaolin,sendData,write failed," + e.getMessage());
                    }
                }
            });
        }
        else{
            Log.i(TAG,"mSocket is null");
        }

        return true;
    }

    int mTotalSize = 0;
    int mFrameSize = 0;
    byte[] mReadBuffer;
    private void readData(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG,"readDatastart");
                while( isAndroidUdpSocketLive ){
                    if( mUdpSocket != null && !mUdpSocket.isClosed()) {
                        try {
                            mUdpSocket.receive(mRecvPacket);
                            String strReceive = new String(mRecvPacket.getData(), 0, mRecvPacket.getLength());
                            int readSize = mRecvPacket.getLength();


                            int head;
                            Log.i(TAG,"readDataread.size()=" + mRecvPacket.getLength());
                            mRecvPacket.setLength(PACKAGE_BUFFER_SIZE);
                            if( readSize > 8 ){
                                head = ((mRecvPacket.getData()[0] & 0xff) << 8) | mRecvPacket.getData()[1];

                                if( head == 0xA66A ){
                                    //Start
                                    mFrameSize = ( (mRecvPacket.getData()[3] & 0xff) << 24 | (mRecvPacket.getData()[4] & 0xff) << 16 | (mRecvPacket.getData()[5] & 0xff) << 8 | (mRecvPacket.getData()[6] & 0xff) );
                                    if(mFrameSize >= 0){
                                        mReadBuffer = new byte[mFrameSize + 8];
                                    }
                                    mTotalSize = 0;
                                }

                                if( mTotalSize < mFrameSize + 8 && (mTotalSize + readSize) <= mFrameSize + 8)
                                {
                                    System.arraycopy(mRecvPacket.getData(), 0, mReadBuffer, mTotalSize, readSize);
                                    mTotalSize += readSize;
                                    if( mTotalSize == mFrameSize + 8){
                                        //End
                                        byte[] imageBuffer = new byte[mFrameSize];
                                        System.arraycopy(mReadBuffer, 8, imageBuffer, 0, mFrameSize);
                                        mFrameSize = 0;
                                        Log.i(TAG,"readDatam,TotalSize=" + mTotalSize);
                                        Log.i(TAG,"readData,imageBuffer.size=" + imageBuffer.length);
                                        Message msg = new Message();
                                        msg.what = AudioFragment.UPDATE_UI;
                                        msg.obj = imageBuffer;
                                        AudioFragment.mCarHandler.sendMessage(msg);
                                    }
                                }
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunxiaolin2016

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值