Esptouch Android代码

    

UDP通信协议是Socket通信的一种实现方式,Socket通信一般有两种通信方式:基于TCP协议基于UDP协议

基本原理

基于UDP的通信都是通过java.net.DatagramSocket这个类来实现的,常用的有connect()、disConnect()、send()、receive()几个方法。DatagramPacket是数据的载体。

DatagramSocket:
public DatagramSocket()throws SocketException {
    this(0);
}

public DatagramSocket(int aPort)throws SocketException {
    checkPort(aPort);
    createSocket(aPort, Inet4Address.ANY);
}

public DatagramSocket(int aPort, InetAddress addr)throws SocketException {
    checkPort(aPort);
    createSocket(aPort, (addr == null) ? Inet4Address.ANY : addr);
}

三个构造方法,我们可以指定端口和IP,也可以不指定,在发送数据的时候,在数据包中指定。

DatagramPacket:
public DatagramPacket(byte[]data, int length) {…}
public DatagramPacket(byte[]data, int offset, int length) {…}
public DatagramPacket(byte[]data, int offset, int length, InetAddress host, int aPort) {…}
public DatagramPacket(byte[]data, int length, InetAddress host, int port) {…}

我们可以看到可以在数据包中设置ip和端口,所以如果连接时不指定也是可以的

基本操作

1、 connect new出一个DatagramSocket对象,设置端口和IP,connect();

2、 send 创建一个DatagramPacket对象,socket.send(packet)发送数据;

3、 receive 创建一个DatagramPacket对象,socket.receive(package)接收数据;

创建一个client连接

构参:

public UDPSocketClient() {
   try {
      this.mSocket = new DatagramSocket();
      this.mIsStop = false;
      this.mIsClosed = false;
   } catch (SocketException e) {
      if (__IEsptouchTask.DEBUG) {
         Log.e(TAG, "SocketException");
      }
      e.printStackTrace();
   }
}

发送函数:

public void sendData(byte[][] data, int offset, int count,
			String targetHostName, int targetPort, long interval) {
		if ((data == null) || (data.length <= 0)) {
			if (__IEsptouchTask.DEBUG) {
				Log.e(TAG, "sendData(): data == null or length <= 0");
			}
			return;
		}
		for (int i = offset; !mIsStop && i < offset + count; i++) {
			if (data[i].length == 0) {
				continue;
			}
			try {
				// Log.i(TAG, "data[" + i + " +].length = " + data[i].length);
				DatagramPacket localDatagramPacket = new DatagramPacket(
						data[i], data[i].length,
						InetAddress.getByName(targetHostName), targetPort);
				this.mSocket.send(localDatagramPacket);
			} catch (UnknownHostException e) {
				if (__IEsptouchTask.DEBUG) {
					Log.e(TAG, "sendData(): UnknownHostException");
				}
				e.printStackTrace();
				mIsStop = true;
				break;
			} catch (IOException e) {
				if (__IEsptouchTask.DEBUG) {
					Log.e(TAG, "sendData(): IOException, but just ignore it");
				}
				// for the Ap will make some troubles when the phone send too many UDP packets,
	            // but we don't expect the UDP packet received by others, so just ignore it
			}
			try {
				Thread.sleep(interval);
			} catch (InterruptedException e) {
				e.printStackTrace();
				if (__IEsptouchTask.DEBUG) {
					Log.e(TAG, "sendData is Interrupted");
				}
				mIsStop = true;
				break;
			}
		}
		if (mIsStop) {
			close();
		}
	}

我们略去他处理IP等信息的复杂算法

看到this.mSocket.send(localDatagramPacket);

代码,则是将UDP广播发送核心代码

创建一个server连接

构参

public UDPSocketServer(int port, int socketTimeout, Context context) {
		this.mContext = context;
		this.buffer = new byte[64];
		this.mReceivePacket = new DatagramPacket(buffer, 64);
		try {
			this.mServerSocket = new DatagramSocket(port);
			this.mServerSocket.setSoTimeout(socketTimeout);
			this.mIsClosed = false;
			WifiManager manager = (WifiManager) mContext
					.getSystemService(Context.WIFI_SERVICE);
			mLock = manager.createMulticastLock("test wifi");
			Log.d(TAG, "mServerSocket is created, socket read timeout: "
					+ socketTimeout + ", port: " + port);
		} catch (IOException e) {
			Log.e(TAG, "IOException");
			e.printStackTrace();
		}
	}

接收代码

public byte[] receiveSpecLenBytes(int len) {
		Log.d(TAG, "receiveSpecLenBytes() entrance: len = " + len);
		try {
			acquireLock();
			mServerSocket.receive(mReceivePacket);
			byte[] recDatas = Arrays.copyOf(mReceivePacket.getData(), mReceivePacket.getLength());
			Log.d(TAG, "received len : " + recDatas.length);
			for (int i = 0; i < recDatas.length; i++) {
				Log.e(TAG, "recDatas[" + i + "]:" + recDatas[i]);
			}
			Log.e(TAG, "receiveSpecLenBytes: " + new String(recDatas));
			if (recDatas.length != len) {
				Log.w(TAG,
						"received len is different from specific len, return null");
				return null;
			}
			return recDatas;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

核心代码mServerSocket.receive(mReceivePacket);接收数据

向上推,调用此方法的对象_EsptouchTask的_ListenAsyn

异步线程Thread,while循环中,可以想到,若要做到通讯,那么必会用到线程,因为项目配置是只进行一次的,不是即时通讯的项目,不涉及线程问题。所以从逻辑上最好不要在同一个线程里发送和接收数据,分别创建两个线程

例:

发送线程:

public class SendThread extends Thread {
    @ Override
    public void run() {
        super.run();
        try {
            if (mSocket == null || mSocket.isClosed())
                return;
            if (messageQueue.size() < 1)
                return;
            //发送
            final String data = messageQueue.get(0);
            byte[]datas = data.getBytes();
            InetAddress address = InetAddress.getByName(Command.udp_address);
            final DatagramPacket packet = new DatagramPacket(datas, datas.length, address, Command.udp_port);
            mSocket.send(packet);
            Logs.e("ConnectManager", "send success data is:" + data);
            messageQueue.remove(0);

        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

接收线程:

private class ReceiveThread extends Thread {
    @ Override
    public void run() {
        super.run();
        if (mSocket == null || mSocket.isClosed())
            return;
        try {
            byte datas[] = new byte[512];
            DatagramPacket packet = new DatagramPacket(datas, datas.length, address, Command.udp_port);
            mSocket.receive(packet);
            String receiveMsg = new String(packet.getData()).trim();
            Logs.e("ConnectManager", "receive msg data is:" + receiveMsg);
            mHandler.sendEmptyMessage(2);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

mHandler.sendEmptyMessage(2)用来重启线程


我们回到demo

在Activity中,点击配置按钮会触发一下AsyncTask,

AsyncTask的onPreExecute()方法不看,doInBackground方法,

@Override
		protected List doInBackground(String... params) {
			int taskResultCount = -1;
			synchronized (mLock) {
				// !!!NOTICE
				String apSsid = mWifiAdmin.getWifiConnectedSsidAscii(params[0]);
				String apBssid = params[1];
				String apPassword = params[2];
				String taskResultCountStr = params[3];
				taskResultCount = Integer.parseInt(taskResultCountStr);
				mEsptouchTask = new EsptouchTask(apSsid, apBssid, apPassword, EsptouchDemoActivity.this);
				mEsptouchTask.setEsptouchListener(myListener);
			}
			List resultList = mEsptouchTask.executeForResults(taskResultCount);
			return resultList;
		}

看方法;

mEsptouchTask.executeForResults(taskResultCount);

此方法回到上面的发送数据中,

此方法完成后主线程更新UI

@Override
		protected void onPostExecute(List result) {
			mProgressDialog.getButton(DialogInterface.BUTTON_POSITIVE)
					.setEnabled(true);
			mProgressDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText(
					"Confirm");
			IEsptouchResult firstResult = result.get(0);
			// check whether the task is cancelled and no results received
			if (!firstResult.isCancelled()) {
				int count = 0;
				// max results to be displayed, if it is more than maxDisplayCount,
				// just show the count of redundant ones
				final int maxDisplayCount = 5;
				// the task received some results including cancelled while
				// executing before receiving enough results
				if (firstResult.isSuc()) {
					StringBuilder sb = new StringBuilder();
					for (IEsptouchResult resultInList : result) {
						sb.append("Esptouch success, bssid = "
								+ resultInList.getBssid()
								+ ",InetAddress = "
								+ resultInList.getInetAddress()
										.getHostAddress() + "\n");
						count++;
						if (count >= maxDisplayCount) {
							break;
						}
					}
					if (count < result.size()) {
						sb.append("\nthere's " + (result.size() - count)
								+ " more result(s) without showing\n");
					}
					mProgressDialog.setMessage(sb.toString());
				} else {
					mProgressDialog.setMessage("Esptouch fail");
				}
			}
		}

此时在Dialog中展示需要的信息,配置成功






你可能感兴趣的:(Esptouch Android代码)