Android -- wifi与socket

来源:互联网 发布:淘宝举报卖家卖违法 编辑:程序博客网 时间:2024/06/05 14:39

最近项目需求要做一个手机、PC建立wifi连接,并通过socket通信的功能。记录一下相关的代码。

1.WifiManager类

        mWifiManager = (WifiManager) getActivity().getSystemService(Context.WIFI_SERVICE);        mWifiInfo = mWifiManager.getConnectionInfo();        mWifiName = mWifiInfo.getSSID();        mIpAddress = intToIp(mWifiInfo.getIpAddress());

WifiManager是一个wifi管理类,可以通过wifiManager得到wifiInfo类,进一步得到ip地址、wifi速率等信息。注意,得到的ip地址是本机被分配的ip地址。


2.建立Socket连接

经过分析,项目决定用Tcp协议进行通信,Java中Socket类自行封装了Tcp协议,可以直接使用。

mSocket = new Socket(mIpAddress, Integer.valueOf(mIpPort));                mInputStream = mSocket.getInputStream();                mOutputStream = mSocket.getOutputStream();

项目中,手机作为客户端主动连接PC热点,连接成功后获得输入输出流(服务器端用accept监听端口的socket连接),注意网络通信需要另起线程,不然Android会编译不过(阻塞主线程)。


3.InputStream的阻塞IO方法读取data

 while(mIsConnected) {                    byte[] buffer = new byte[1024];                    while ((mInputStream.read(buffer)) != -1) {                        ......                    }}

用一个标志位mIsConnected控制循环,注意mInputStream.read(buffer)是一个阻塞方法(会让线程一直停留在读取操作上),并且在网络通信中,除非手动关闭socket,否则不会返回-1(如果是文件流读取,读到文件末尾时会返回-1)。

当发送的数据不定长时,数据读取会比较麻烦,可以自己定一个消息格式,将data按数据包的形式发送,数据包一般包括的字段有:head、dataLength、data、end。

当数据长度过大时,可以用以下方法读到一个buffer中。

byte[] buffer = new byte[ mDataLen];int readLen = 0;try {while (readLen < buffer.length) {int result = mInputStream.read(buffer, readLen, buffer.length - readLen);if (result == -1) {continue;}readLen = readLen + result;}

4.线程池与OutputStream

本项目中,我单独起了一个线程来处理Output操作。我将待发送的数据保存到mDataPool中(资源池,是一个队列),若资源池不为空,则向outputStream中write数据。

while () {    byte[] data = null;    synchronized (mDataPool) {        data = mDataPool.poll();    }    if (data == null) {        continue;    }    try {        mOutputStream.flush();        mOutputStream.write(data));    } catch (IOException e) {        e.printStackTrace();    }}

5.IP地址转换和有效性检查

    private String intToIp(int ipAddr) {        StringBuilder sb = new StringBuilder();        sb.append(ipAddr & 0xFF).append(".");        sb.append((ipAddr >> 8) & 0xFF).append(".");        sb.append((ipAddr >> 16) & 0xFF).append(".");        sb.append((ipAddr >> 24) & 0xFF);        return sb.toString();    }    private boolean checkIP(String str) {        Pattern pattern = Pattern                .compile("^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]"                        + "|[*])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]|[*])$");        return pattern.matcher(str).matches();    }


6.Wifi与热点

注意,wifi与热点不能同时启动,打开热点必须先关闭Wifi,且热点相关的方法是WifiManager的hiden方法,需要用反射来调用。

监听热点是否开启:

public enum WIFI_AP_STATE {    WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_ENABLING,  WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_FAILED}    private WIFI_AP_STATE getWifiApState(){    int tmp;    try {        Method method = mWifiManager.getClass().getMethod("getWifiApState");        tmp = ((Integer) method.invoke(mWifiManager));        if (tmp > 10) {            tmp = tmp - 10;        }        return WIFI_AP_STATE.class.getEnumConstants()[tmp];    } catch (Exception e) {        e.printStackTrace();        return WIFI_AP_STATE.WIFI_AP_STATE_FAILED;    }}




0 0