安卓Socket使用之服务器端

本文介绍了一个基于Android系统的应用程序,该程序能够创建WiFi热点并实现客户端与服务器之间的文件传输功能。通过反射调用Android系统API,实现了热点的创建与管理,并通过Socket编程实现了文件的发送与接收。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MainActivity.java:

package itant.com.wifiserver;

import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
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.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringBufferInputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView tv_status;
    private TextView tv_content;
    private boolean isClientConnected;

    private static final int CLIENT_DISCONNECTED = 0;
    private static final int CLIENT_CONNECTED = 1;
    private static final int HOT_SPOT_READY = 2;
    private static final int MSG_FROM_CLIENT = 3;
    private WifiManager mWifiManager;

    private Handler mServerHandler = new Handler(new Handler.Callback() {

        @Override
        public boolean handleMessage(Message msg) {
            // TODO Auto-generated method stub
            switch (msg.what) {
                case CLIENT_DISCONNECTED:
                    // 断开
                    isClientConnected = false;
                    break;
                case CLIENT_CONNECTED:
                    // 客户端连上了
                    tv_status.setText("已连接");
                    isClientConnected = true;
                    break;
                case HOT_SPOT_READY:
                    // 热点创建成功,开启socket服务器端,监听客户端连接(监听断开)
                    new ServerThread().start();
                    break;

                case MSG_FROM_CLIENT:
                    if (msg.obj != null) {
                        tv_content.setText(msg.obj.toString());
                    } else {
                        tv_content.setText("null" + System.currentTimeMillis());
                    }

                    break;
                default:
                    break;
            }
            return true;
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

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

        tv_status  = (TextView) findViewById(R.id.tv_status);
        tv_content  = (TextView) findViewById(R.id.tv_content);

        findViewById(R.id.btn_create_wifi).setOnClickListener(this);
        findViewById(R.id.btn_send).setOnClickListener(this);
    }

    private void createWIFI(String hotSpotName, String password) {
        if (mWifiManager.isWifiEnabled()) {
            // 如果开启了WIFI,则将它关闭
            mWifiManager.setWifiEnabled(false);
        }

        try{
            WifiConfiguration wifiConfiguration = new WifiConfiguration();
            //热点名称
            wifiConfiguration.SSID = hotSpotName;
            //热点密码
            wifiConfiguration.preSharedKey = password;
            wifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
            wifiConfiguration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
            wifiConfiguration.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
            wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
            wifiConfiguration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
            wifiConfiguration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
            wifiConfiguration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            wifiConfiguration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);

            // 利用反射获取开启热点的方法创建热点
            HttpTools.setWifiApEnabled(mWifiManager, wifiConfiguration, true);

            final Method isHotSpotEnable = mWifiManager.getClass().getMethod("isWifiApEnabled");

            // 每隔1.5秒查看热点是否创建成功
            new Thread(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    while (true) {
                        try {
                            boolean hotSpotEnable = (boolean) isHotSpotEnable.invoke(mWifiManager);
                            if (hotSpotEnable) {
                                mServerHandler.sendEmptyMessage(HOT_SPOT_READY);
                                break;
                            }
                            Thread.sleep(1500);
                        } catch (Exception e) {
                            // TODO: handle exception
                        }
                    }
                }
            }).start();
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    private ServerSocket mServerSocket;
    private boolean mIsServiceDestoryed = false;
    /**往客户端发送文件的入口**/
    private DataOutputStream mOutputStream;

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_create_wifi:
                // 创建热点
                String hotSpotName = "backup" + System.currentTimeMillis();
                String password = "away6899";
                createWIFI(hotSpotName, password);
                break;

            case R.id.btn_send:
                if (!isClientConnected) {
                    Toast.makeText(this, "等待连接", Toast.LENGTH_SHORT).show();
                    return;
                }
                // 发送信息
                String str = "hello moto";
                try {
                    // 把文件名告诉客户端
                    //mOutputStream.writeUTF(app.getAppName() + ".apk");
                    //mOutputStream.flush();

                    byte[] strBytes = str.getBytes("UTF-8");
                    // 把长度诉客户端,否则不知道一个文件结尾在哪。千万不要直接传str.length()!!!因为我们采用的
                    // 是UTF-8编码,其长度是有所区别的,如果直接传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;
        }
    }

    /**
     * Socket服务器端
     * @author 詹子聪
     */
    private class ServerThread extends Thread {

        @Override
        public void run() {
            try {
                mServerSocket = new ServerSocket(8688);
            } catch (IOException e) {
                System.err.println("establish tcp server failed, port:8688");
                e.printStackTrace();
                return;
            }

            while (!Thread.currentThread().isInterrupted()) {
                try {
                    // 一个客户端连接上了
                    final Socket mClient = mServerSocket.accept();
                    mOutputStream = new DataOutputStream(mClient.getOutputStream());
                    mServerHandler.sendEmptyMessage(CLIENT_CONNECTED);
                    CommunicationThread commThread = new CommunicationThread(mClient);
                    new Thread(commThread).start();

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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mIsServiceDestoryed = true;

        // 关闭流
        if (mServerSocket != null) {
            try {
                if (mOutputStream != null) {
                    mOutputStream.close();
                }
                mServerSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    class CommunicationThread implements Runnable {
        private Socket clientSocket;
        private BufferedReader input;
        public CommunicationThread(Socket clientSocket) {
            this.clientSocket = clientSocket;
            try {
                this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));

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

        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                /*try {
                    String read = input.readLine();
                    System.out.println("获取到客户端的信息:" + read);
                    Message message = Message.obtain();
                    message.what = MSG_FROM_CLIENT;
                    message.obj = read;
                    mServerHandler.sendMessage(message);
                } catch (IOException e) {
                    e.printStackTrace();
                }*/
                try {
                    // 接收客户端的消息和文件
                    DataInputStream inputStream = new DataInputStream(new BufferedInputStream(this.clientSocket.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 = MSG_FROM_CLIENT;
                        mServerHandler.sendMessage(message);
                    }
                    System.out.println("quit...");
                    this.clientSocket.close();
                } catch (Exception 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_create_wifi"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="创建热点"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <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.wifiserver">

    <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.wifiserver;

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;
    }
    /*****************************供接收者使用***************************************/
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ithouse

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

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

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

打赏作者

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

抵扣说明:

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

余额充值