安卓Socket使用之客户端

MainActivity.java:

package itant.com.wificlient;

import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView tv_status;
    private TextView tv_content;

    // 10秒扫描一次
    private static final int WAIT_FOR_SCAN_RESULT = 5 * 1000;
    // 20秒之内没有得到扫描结果就不要再扫描了
    private static final int WIFI_SCAN_TIMEOUT = 200 * 1000;

    private static final int CONNECT_SERVER_SUC = 1;
    private static final int RECEIVED_MSG = 2;
    private Socket mClientSocket;

    private WifiManager mWifiManager;
    private Handler mConnectHotSpotHandler = new Handler(new Handler.Callback() {

        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case CONNECT_SERVER_SUC:
                    //Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).show();
                    tv_status.setText("连接成功");
                    // WiFi连接成功,开socket客户端去连接服务器以接收文件
                    final String serverIP = HttpTools.getSenderIP(mWifiManager);
                    new Thread(new Runnable() {

                        @Override
                        public void run() {
                            connectTCPServer(serverIP);
                        }
                    }).start();
                    break;

                case RECEIVED_MSG:
                    tv_content.setText(msg.obj.toString());
                    break;
                default:
                    //Toast.makeText(MainActivity.this, "连接失败", Toast.LENGTH_SHORT).show();
                    break;
            }
            return true;
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_status = (TextView) findViewById(R.id.tv_status);
        tv_content = (TextView) findViewById(R.id.tv_content);
        findViewById(R.id.btn_connect).setOnClickListener(this);
        findViewById(R.id.btn_send).setOnClickListener(this);

        mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_connect:
                // 搜索并连接我们APP创建的热点
                if (mWifiManager != null) {
                    mWifiManager.setWifiEnabled(false);
                }
                new ConnectTask().execute();
                break;
            case R.id.btn_send:
                if (mClientSocket != null) {
                    /*try {
                        String str = "I am client";
                        PrintWriter out = new PrintWriter(new BufferedWriter(
                                new OutputStreamWriter(mClientSocket.getOutputStream())),
                                true);
                        out.println(str);
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }*/

                    // 发送信息
                    /*String str = "hello server --客户端";
                    try {
                        DataOutputStream mOutputStream = new DataOutputStream(mClientSocket.getOutputStream());
                        // 把文件名告诉服务端
                        //mOutputStream.writeUTF(app.getAppName() + ".apk");
                        //mOutputStream.flush();

                        // 把长度诉服务端,否则不知道一个文件结尾在哪
                        mOutputStream.writeLong(str.length());
                        mOutputStream.flush();

                        DataInputStream inputStream = new DataInputStream(
                                new ByteArrayInputStream(str.getBytes("UTF-8")));
                        byte buf[] = new byte[1024];
                        int len = -1;

                        while ((len = inputStream.read(buf)) != -1) {
                            mOutputStream.write(buf, 0, len);
                        }
                        mOutputStream.flush();
                        inputStream.close();
                        // 发送结束了
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }*/

                    String str = "hello server --客户端";
                    try {
                        DataOutputStream mOutputStream = new DataOutputStream(mClientSocket.getOutputStream());
                        // 把文件名告诉服务端
                        //mOutputStream.writeUTF(app.getAppName() + ".apk");
                        //mOutputStream.flush();

                        byte[] strBytes = str.getBytes("UTF-8");

                        // 把长度诉服务端,否则不知道一个文件结尾在哪。千万不要直接传str.length()!!!因为我们采用的
                        // 是UTF-8编码,其长度是有所区别的,如果直接传str.length()很可能会导致传递的数据不完整!
                        //mOutputStream.writeLong(str.length());
                        mOutputStream.writeLong(strBytes.length);
                        mOutputStream.flush();

                        DataInputStream inputStream = new DataInputStream(
                                new ByteArrayInputStream(strBytes));
                        byte buf[] = new byte[1024];
                        int len = -1;

                        while ((len = inputStream.read(buf)) != -1) {
                            mOutputStream.write(buf, 0, len);
                        }
                        mOutputStream.flush();
                        inputStream.close();
                        // 发送结束了
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }

                    Toast.makeText(this, "发送完毕", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

    /**
     * 连接特定热点
     * @param passwd 密码
     */
    private void connectToHotSpot(String passwd, int type) {
        // 关闭热点
        HttpTools.setWifiApEnabled(mWifiManager, null, false);

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 打开WiFi
        mWifiManager.setWifiEnabled(true);

        List<ScanResult> scanResults = mWifiManager.getScanResults();
        if (scanResults == null) {
            // 如果没有可用的扫描结果,激活扫描
            mWifiManager.startScan();
            boolean isScanResultIsAvailable = false;
            long startTime = System.currentTimeMillis();
            while (!isScanResultIsAvailable) {
                if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
                    // 20秒之内还没搜到可用热点就不要再搜了
                    return;
                }

                // 等待扫描结果,等5秒之后查看结果
                synchronized (this) {
                    try {
                        this.wait(WAIT_FOR_SCAN_RESULT);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    if ((mWifiManager.getScanResults() == null) || (mWifiManager.getScanResults().size() <= 0)) {
                        continue;
                    }
                    isScanResultIsAvailable = true;
                }
            }
        }

        // 获取扫描结果(代码能走到这里一定有结果了)
        scanResults = mWifiManager.getScanResults();
        for (ScanResult scanResult : scanResults) {
            // 如果当前这个热点是我们想要连接的热点,那么就连接它
            if (scanResult.SSID.startsWith("backup")) {
                final String ssid = "\"" + scanResult.SSID + "\"";
                WifiConfiguration wifiConfiguration = HttpTools.createWifiInfo(ssid, passwd, type);
                int networkId = mWifiManager.addNetwork(wifiConfiguration);
                // 连接特定热点,并断开其他连接
                mWifiManager.enableNetwork(networkId, true);
                mWifiManager.saveConfiguration();
                //mWifiManager.disconnect();
                mWifiManager.reconnect();
                // 开一个线程去轮询连接情况
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        while (true) {
                            if (HttpTools.isWiFiConnected(MainActivity.this)) {
                                // 已经连接上的热点真的是我们想要连接的热点
                                if (TextUtils.equals(ssid, HttpTools.getConnectedWifiSsid(mWifiManager))) {
                                    mConnectHotSpotHandler.sendEmptyMessage(CONNECT_SERVER_SUC);
                                    break;
                                }
                            } else {
                                // 当前连接的WiFi不是我们想要的,重新连接
                                connectToHotSpot("away6899", HttpTools.TYPE_WPA);
                            }

                            // 割两秒去查一下是否已经连上了WiFi
                            try {
                                Thread.sleep(2000);
                            } catch (Exception e) {
                                // TODO: handle exception
                            }
                        }
                    }
                }).start();
                break;
            } else {
                // 不是我们的热点就断开连接
                //mWifiManager.disconnect();
            }
        }
    }

    /**
     * 后台搜索并连接热点
     * @author 詹子聪
     */
    private class ConnectTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            // TODO Auto-generated method stub
            connectToHotSpot("away6899", HttpTools.TYPE_WPA);
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
        }
    }

    /**
     * 连接服务器,从服务器接收应用
     *
     * @param serverIP
     */
    private void connectTCPServer(String serverIP) {
        Socket socket = null;
        while (socket == null) {
            try {
                socket = new Socket(serverIP, 8688);
                mClientSocket = socket;
            } catch (IOException e) {
                SystemClock.sleep(1000);
                System.out.println("connect tcp server failed, retry...");
            }
        }

        try {
            // 接收服务器端的消息和文件
            DataInputStream inputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

            // 不断地监听,看服务器是否有东西过来
            while (!MainActivity.this.isFinishing()) {
                //String fileName = inputStream.readUTF();
                long fileSize = inputStream.readLong();
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                DataOutputStream outputStream = new DataOutputStream(
                        new BufferedOutputStream(out));

                byte[] buffer = new byte[(int) fileSize];
                int nIdx = 0;
                int nTotalLen = buffer.length;
                int nReadLen = 0;

                while (nIdx < nTotalLen) {
                    // 从nIdx开始,想读nTotalLen - nIdx那么多,实际上这次读了nReadLen
                    nReadLen = inputStream.read(buffer, nIdx, nTotalLen - nIdx);

                    if (nReadLen > 0) {
                        outputStream.write(buffer, nIdx, nReadLen);
                        nIdx = nIdx + nReadLen;
                    } else {
                        break;
                    }
                }
                outputStream.close();
                String str = out.toString();
                Message message = Message.obtain();
                message.obj = str;
                message.what = RECEIVED_MSG;
                mConnectHotSpotHandler.sendMessage(message);

            }
            System.out.println("quit...");
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mClientSocket != null) {
            try {
                mClientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_status"
        android:text="未连接"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>


    <Button
        android:id="@+id/btn_connect"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="连接服务器"/>

    <Button
        android:id="@+id/btn_send"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送"
        android:layout_marginTop="16dp"/>
</LinearLayout>

清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="itant.com.wificlient">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!-- 文件存储 -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

HttpTools.java:

package itant.com.wificlient;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.text.format.Formatter;

import java.lang.reflect.Method;

/**
 * 网络请求相关辅助类
 * @author jason.zhan
 *
 */
public class HttpTools {

    /**
     * 判断是否有网络
     * @param context
     * @return
     */
    public static boolean isNetworkConnected(Context context) {
        if (context != null) {  
            ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
            if (mNetworkInfo != null) {  
                return mNetworkInfo.isAvailable();  
            }  
        }  
        return false;  
    }

    public static boolean setWifiApEnabled(WifiManager wifiManager, WifiConfiguration wifiConfiguration, boolean enable) {
        boolean invokeStatus = true;
        try {
            Method setupHotSpot = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
            setupHotSpot.invoke(wifiManager, wifiConfiguration, enable);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            invokeStatus = false;
        }

        return invokeStatus;
    }


    /**
     * 判断WiFi是否连接上了
     * @param context
     * @return
     */
    public static boolean isWiFiConnected(Context context) {
        if (context != null) {  
            ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
            if (mNetworkInfo != null) {
                return (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
            }  
        }  
        return false;  
    }

    /**
     * 获取所连接的WiFi名称
     * @param wifiManager
     * @return
     */
    public static String getConnectedWifiSsid(WifiManager wifiManager) {
        return wifiManager.getConnectionInfo().getSSID();  
    }  

    /**
     * @return (发送端)服务器IP地址,转换IP输出格式
     */
    public static String getSenderIP(WifiManager wifiManager) {
        //WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        //int ipAddress = wifiInfo.getIpAddress();  
        int ipAddress = wifiManager.getDhcpInfo().serverAddress;

        return Formatter.formatIpAddress(ipAddress);
    }

    /*****************************供接收者使用***************************************/
    // 加密类型,分为三种情况:1.没有密码   2.用WEP加密    3.用WPA加密,我们这里只用到了第3种
    public static final int TYPE_NO_PASSWD = 1;
    public static final int TYPE_WEP = 2;
    public static final int TYPE_WPA = 3;
    /**
     * 连接信息生成配置对象
     */
    public static WifiConfiguration createWifiInfo(String SSID, String password, int type) {
        WifiConfiguration config = new WifiConfiguration();
        config.SSID = SSID;
        // 清除热点记录clearAll(SSID);
        if (type == TYPE_NO_PASSWD) {
            config.hiddenSSID = false;
            config.status = WifiConfiguration.Status.ENABLED;
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
            config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.preSharedKey = null;
        } else if (type == TYPE_WEP) {
            config.hiddenSSID = true;
            config.wepKeys[0] = "\"" + password + "\"";
            config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            config.wepTxKeyIndex = 0;
        } else if (type == TYPE_WPA) {
            config.preSharedKey = "\"" + password + "\"";
            config.hiddenSSID = false;
            config.priority = 10000;
            config.status = WifiConfiguration.Status.ENABLED;

            config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
            config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
            config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
        }

        return config;
    }
    /*****************************供接收者使用***************************************/
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ithouse

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

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

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

打赏作者

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

抵扣说明:

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

余额充值