android端基于socket的局域网内服务器与客户端加密通信

原创 2017年04月13日 00:51:52

android端基于socket的局域网内服务器与客户端加密通信

实现了基本的socket通信(即两台设备,一台用作服务器,一台用作客户端),服务器进行监听,客户端发送加密数据到服务器,服务器进行解密得到明文。

注意:本项目中使用了ButterKnife及EventBus作为辅助工具,通信建立时默认网络正常(未做局域网网络环境检测),加密方式为AES加密

1.效果图:

(1)客户端

客户端

(2)服务器端

服务器端

2.界面布局部分

(1)服务器端布局 function_socket_server.xml

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

    <RelativeLayout style="@style/ToolBar">

        <TextView
            style="@style/ToolBar_tv_Title"
            android:text="网络加密-服务器端" />


    </RelativeLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_startListener"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="启动监听" />


        <Button
            android:id="@+id/btn_stopListener"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="停止监听" />

        <Button
            android:id="@+id/btn_getUser"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="刷新用户" />
    </LinearLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="10dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="本机地址:" />

        <TextView
            android:id="@+id/tv_localAddress"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:singleLine="true" />
    </LinearLayout>


    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">


            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="接收到的明文:"
                android:textColor="@color/black" />

            <TextView
                android:id="@+id/tv_receivedContent"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:padding="10dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="解密后的明文:"
                android:textColor="@color/black" />

            <TextView
                android:id="@+id/tv_decryptContent"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:padding="10dp" />
        </LinearLayout>

    </ScrollView>

</LinearLayout>

(2)客户端布局 function_socket_client.xml

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

    <RelativeLayout style="@style/ToolBar">

        <TextView
            style="@style/ToolBar_tv_Title"
            android:text="网络加密-客户端" />


    </RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="10dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="服务器地址:" />

        <EditText
            android:id="@+id/edtTxt_serverAddress"
            android:layout_width="match_parent"
            android:text="192.168.43.1"
            android:layout_height="wrap_content"
            android:singleLine="true" />
    </LinearLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">


            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="文本内容:"
                android:textColor="@color/black" />

            <EditText
                android:id="@+id/edtTxt_Content"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/main_background"
                android:padding="10dp"
                android:text="123木头人" />
        </LinearLayout>
    </ScrollView>

    <Button
        android:id="@+id/btn_encryptAndSend"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:text="加密并发送" />
</LinearLayout>

(3)用到的style

 <!--通用Title的右侧按钮-->
    <style name="ToolBar_iv_Right">
        <item name="android:layout_width">@dimen/toolbar_icon_dimen</item>
        <item name="android:layout_height">@dimen/toolbar_icon_dimen</item>
        <item name="android:layout_alignParentRight">true</item>
        <item name="android:layout_gravity">end</item>
        <item name="android:clickable">true</item>
        <item name="android:background">?android:actionBarItemBackground</item>
        <item name="android:padding">15dp</item>
    </style>
    <!--通用Title的TextView-->
    <style name="ToolBar_tv_Title">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_centerVertical">true</item>
        <item name="android:layout_marginLeft">@dimen/toolbar_title_haveBack_marginStart</item>
        <item name="android:layout_marginRight">@dimen/toolbar_title_haveBack_marginEnd</item>
        <item name="android:gravity">center</item>
        <item name="android:singleLine">true</item>
        <item name="android:textColor">@color/white</item>
        <item name="android:textSize">20sp</item>
    </style>

(4) 用到的样式
dimens.xml

<dimen name="toolbar_title_haveBack_marginStart">55dp</dimen>
    <dimen name="toolbar_title_haveBack_marginEnd">55dp</dimen>

colors.xml

    <color name="colorPrimary">#03A9F4</color>
    <color name="colorPrimaryDark">#0288D1</color>
    <color name="colorAccent">#FF4081</color>
    <color name="colorPrimaryLight">#B3E5FC</color>

3.功能代码
(1)基类 BaseEventActivity.java


import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import org.greenrobot.eventbus.EventBus;

import butterknife.ButterKnife;

public abstract class BaseEventActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getIntentData();
        setContentView(getLayoutResId());
        ButterKnife.bind(this);
        EventBus.getDefault().register(this);
        init();
    }

    protected void getIntentData() {
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    protected abstract void init();

    protected abstract int getLayoutResId();
}

(2)服务器主界面 Function_Socket.java

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.view.View;
import android.widget.TextView;


import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;

import butterknife.BindView;
import butterknife.OnClick;

/**
 * 服务器界面
 */
public class Function_Socket_Server extends BaseEventActivity {
    @BindView(R.id.tv_localAddress)
    TextView tv_localAddress;
    @BindView(R.id.tv_receivedContent)
    TextView tv_receivedContent;
    @BindView(R.id.tv_decryptContent)
    TextView tv_decryptContent;
    private LocalService localService;//用于启动监听的服务
    private ServiceConnection sc;//服务连接

    @Override
    protected void init() {
        tv_localAddress.setText(ToolUtil.getHostIP());
        sc = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                LocalService.LocalBinder localBinder = (LocalService.LocalBinder) service;
                localService = localBinder.getService();
                localService.startWaitDataThread();
                ToastUtil.showToast(Function_Socket_Server.this, "监听已启动");
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        };
        connection();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void getData(String data) {
        tv_receivedContent.setText(data);
        tv_decryptContent.setText(AESUtil.decrypt(ConstantUtil.password, data));
    }

    /**
     * 绑定service
     */
    private void connection() {
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, sc, BIND_AUTO_CREATE);
    }

    @Override
    protected int getLayoutResId() {
        return R.layout.function_socket_server;
    }

    /**
     * 获取连接到本机热点上的手机ip
     */
    private ArrayList<String> getConnectedIP() {
        ArrayList<String> connectedIP = new ArrayList<>();
        try {
            //通过读取配置文件实现
            BufferedReader br = new BufferedReader(new FileReader(
                    "/proc/net/arp"));
            String line;
            while ((line = br.readLine()) != null) {
                String[] splitted = line.split(" +");
                if (splitted.length >= 4) {
                    String ip = splitted[0];
                    connectedIP.add(ip);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connectedIP;
    }

    @OnClick({R.id.btn_startListener, R.id.btn_stopListener, R.id.btn_getUser})
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_startListener://启动监听
                connection();
                break;
            case R.id.btn_stopListener://停止监听
                if (sc != null)
                    unbindService(sc);
                break;
            case R.id.btn_getUser://刷新连接到此设备的IP并清空之前接收到的数据
                ArrayList<String> connectedIP = getConnectedIP();
                StringBuilder resultList = new StringBuilder();

                for (String ip : connectedIP) {
                    resultList.append(ip);
                    resultList.append("\n");
                }
                ToastUtil.showToast(this, "连接到手机上的Ip是:" + resultList.toString());
                tv_decryptContent.setText("");
                tv_receivedContent.setText("");
                break;
        }
    }


    public void onDestroy() {
        super.onDestroy();
        if (sc != null)
            unbindService(sc);
    }


}

(3)客户端主界面 Function_Socket_Client.java


import android.app.ProgressDialog;
import android.util.Log;
import android.view.View;
import android.widget.EditText;


import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import butterknife.BindView;
import butterknife.OnClick;


/**
 * 客户端界面
 */
public class Function_Socket_Client extends BaseEventActivity {
    @BindView(R.id.edtTxt_Content)
    EditText edtTxt_Content;
    @BindView(R.id.edtTxt_serverAddress)
    EditText edtTxt_serverAddress;

    private ProgressDialog mProgressDialog;//加载的小菊花

    /**
     * 初始化
     */
    @Override
    protected void init() {
    }

    @Override
    protected int getLayoutResId() {
        return R.layout.function_socket_client;
    }


    @OnClick(R.id.btn_encryptAndSend)
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_encryptAndSend:
                String s = edtTxt_Content.getText().toString().trim();
                String ip = edtTxt_serverAddress.getText().toString().trim();
                if (ToolUtil.IsIpv4(ip)) {
                    new SendDataThread(ip, AESUtil.encrypt(ConstantUtil.password, s), ConstantUtil.port).start();//消息发送方启动线程发送消息
                    showProgressDialog("尝试发送数据到\n\t\t" + ip, true);
                } else {
                    ToastUtil.showToast(this, "IP不合法!");
                }
                break;
        }
    }

    /**
     * 连接结果
     *
     * @param resultCode 0:连接超时;1:发送成功 2:失败
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void sendResult(Integer resultCode) {
        Log.i("succ", "=" + resultCode);
        dismissProgressDialog();
        switch (resultCode) {
            case ConstantUtil.CODE_SUCCESS:
                ToastUtil.showToast(this, "发送成功");
                break;
            case ConstantUtil.CODE_TIMEOUT:
                ToastUtil.showToast(this, "连接超时");
                break;
            case ConstantUtil.CODE_UNKNOWN_HOST:
                ToastUtil.showToast(this, "错误-未知的host");
                break;

        }

    }

    /**
     * 数据加载小菊花
     *
     * @param msg      内容
     * @param isCancel 是否允许关闭 true - 允许  false - 不允许
     */
    public void showProgressDialog(final String msg, final boolean isCancel) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    if (mProgressDialog == null) {
                        mProgressDialog = new ProgressDialog(Function_Socket_Client.this);
                    }
                    if (mProgressDialog.isShowing()) {
                        return;
                    }
                    mProgressDialog.setMessage(msg);
                    mProgressDialog.setCancelable(isCancel);
                    mProgressDialog.setCanceledOnTouchOutside(false);
                    mProgressDialog.setOnCancelListener(null);
                    mProgressDialog.show();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 隐藏数据加载的进度小菊花
     **/
    public void dismissProgressDialog() {

        try {
            if (mProgressDialog != null && mProgressDialog.isShowing()) {
                runOnUiThread(
                        new Runnable() {
                            @Override
                            public void run() {
                                mProgressDialog.dismiss();
                            }
                        }
                );
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



}

(4)LocalService.java


import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;


/**
 * 此服务用于启动监听线程
 */
public class LocalService extends Service {
    private IBinder iBinder = new LocalService.LocalBinder();

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    public void startWaitDataThread() {
        new ListenThread(ConstantUtil.port).start();
    }

    //定义内容类继承Binder
    public class LocalBinder extends Binder {
        //返回本地服务
        public LocalService getService() {
            return LocalService.this;
        }
    }
}

(5)ListenThread.java


import org.greenrobot.eventbus.EventBus;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 监听线程
 */
public class ListenThread extends Thread {
    private ServerSocket serverSocket;

    public ListenThread(int port) {
        try {
            serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                if (serverSocket != null) {
                    Socket socket = serverSocket.accept();
                    InputStream inputStream = socket.getInputStream();
                    if (inputStream != null) {
                        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
                        String str;
                        str = in.readLine();
                        EventBus.getDefault().post(str);
                        socket.close();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

(6)SendDataThread.java

import android.util.Log;

import org.greenrobot.eventbus.EventBus;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

/**
 * 数据发送线程
 */
public class SendDataThread extends Thread {
    private Socket socket;
    private String ip;//接收方的IP
    private int port;//接收方的端口号
    private String data;//准备发送的数据

    public SendDataThread(String ip, String data, int port) {
        this.ip = ip;
        this.data = data;
        this.port = port;
    }

    @Override
    public void run() {
        try {
            socket = new Socket();
            socket.connect(new InetSocketAddress(ip,port),ConstantUtil.TIME_MILLIS);//设置超时时间
        } catch (UnknownHostException e) {
            EventBus.getDefault().post(ConstantUtil.CODE_UNKNOWN_HOST);
            Log.d("error", "SendDataThread.init() has UnknownHostException" + e.getMessage());
        } catch (SocketTimeoutException e) {
            EventBus.getDefault().post(ConstantUtil.CODE_TIMEOUT);
            Log.d("error", "SendDataThread.init() has TimeoutException:" + e.getMessage());
        }catch (IOException e){
            Log.d("error", "SendDataThread.init() has IOException:" + e.getMessage());
        }
        if (socket != null&&socket.isConnected()) {
            try {
                OutputStream ops = socket.getOutputStream();
                OutputStreamWriter opsw = new OutputStreamWriter(ops);
                BufferedWriter writer = new BufferedWriter(opsw);
                writer.write(data + "\r\n\r\n");//由于socket使用缓冲区进行读写数据,因此使用\r\n\r\n用于表明数据已写完.不加这个会导致数据无法发送
                EventBus.getDefault().post(ConstantUtil.CODE_SUCCESS);
                writer.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

(7)AESUtil.java

import android.util.Log;

import java.io.UnsupportedEncodingException;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES加密工具类
 */
public class AESUtil {

    //    private static final String CipherMode = "AES/ECB/PKCS5Padding";使用ECB加密,不需要设置IV,但是不安全
    private static final String CipherMode = "AES/CFB/NoPadding";//使用CFB加密,需要设置IV

    /**
     * 生成加密后的密钥
     *
     * @param password 密钥种子
     * @return isSucceed
     */
    private static SecretKeySpec createKey(String password) {
        byte[] data = null;
        if (password == null) {
            password = "";
        }
        StringBuilder sb = new StringBuilder(32);
        sb.append(password);
        while (sb.length() < 32) {
            sb.append("0");
        }
        if (sb.length() > 32) {
            sb.setLength(32);
        }

        try {
            data = sb.toString().getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return new SecretKeySpec(data, "AES");
    }

    // /** 加密字节数据 **/
    private static byte[] encrypt(byte[] content, String password) {
        try {
            SecretKeySpec key = createKey(password);
            System.out.println(key);
            Cipher cipher = Cipher.getInstance(CipherMode);
            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(
                    new byte[cipher.getBlockSize()]));
            return cipher.doFinal(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // /** 加密(结果为16进制字符串) **/
    public static String encrypt(String password, String content) {
        Log.d("加密前", "seed=" + password + "\ncontent=" + content);
        byte[] data = null;
        try {
            data = content.getBytes("UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        data = encrypt(data, password);
        String result = byte2hex(data);
        Log.d("加密后", "result=" + result);
        return result;
    }

    // /** 解密字节数组 **/
    private static byte[] decrypt(byte[] content, String password) {

        try {
            SecretKeySpec key = createKey(password);
            Cipher cipher = Cipher.getInstance(CipherMode);
            cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(
                    new byte[cipher.getBlockSize()]));

            return cipher.doFinal(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // /** 解密16进制的字符串为字符串 **/
    public static String decrypt(String password, String content) {
        Log.d("解密前", "seed=" + password + "\ncontent=" + content);
        byte[] data = null;
        try {
            data = hex2byte(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        data = decrypt(data, password);
        if (data == null)
            return null;
        String result = null;
        try {
            result = new String(data, "UTF-8");
            Log.d("解密后", "result=" + result);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    // /** 字节数组转成16进制字符串 **/
    private static String byte2hex(byte[] b) { // 一个字节的数,
        StringBuilder sb = new StringBuilder(b.length * 2);
        String tmp ;
        for (byte aB : b) {
            // 整数转成十六进制表示
            tmp = (Integer.toHexString(aB & 0XFF));
            if (tmp.length() == 1) {
                sb.append("0");
            }
            sb.append(tmp);
        }
        return sb.toString().toUpperCase(); // 转成大写
    }

    // /** 将hex字符串转换成字节数组 **/
    private static byte[] hex2byte(String inputString) {
        if (inputString == null || inputString.length() < 2) {
            return new byte[0];
        }
        inputString = inputString.toLowerCase();
        int l = inputString.length() / 2;
        byte[] result = new byte[l];
        for (int i = 0; i < l; ++i) {
            String tmp = inputString.substring(2 * i, 2 * i + 2);
            result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
        }
        return result;
    }
}

(8)ConstantUtil.java

/**
 * 常量类
 */
public class ConstantUtil {
    public static final int TIME_MILLIS = 5 * 1000;//连接超时时间
    public static final int port = 25256;//端口号
    public static final String password = "123456885";//加密所使用的密钥
    public static final int CODE_TIMEOUT = 0;//连接超时
    public static final int CODE_SUCCESS = 1;//连接成功
    public static final int CODE_UNKNOWN_HOST = 2;//错误-未知的host
}

(9)ToolUtil.java

import android.util.Log;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;


/**
 * 工具类
 */
public class ToolUtil {
    /**
     * 获取ip地址
     * 如果是移动网络,会显示自己的公网IP,如果是局域网,会显示局域网IP
     * 因此本例中服务器端需要断开移动网络以得到本机局域网IP
     */
    public static String getHostIP() {

        String hostIp = null;
        try {
            Enumeration nis = NetworkInterface.getNetworkInterfaces();
            InetAddress ia;
            while (nis.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface) nis.nextElement();
                Enumeration<InetAddress> ias = ni.getInetAddresses();
                while (ias.hasMoreElements()) {
                    ia = ias.nextElement();
                    if (ia instanceof Inet6Address) {
                        continue;// skip ipv6
                    }
                    String ip = ia.getHostAddress();
                    if (!"127.0.0.1".equals(ip)) {
                        hostIp = ia.getHostAddress();
                        break;
                    }
                }
            }
        } catch (SocketException e) {
            Log.i("error", "SocketException");
            e.printStackTrace();
        }
        return hostIp;

    }

    /**
     * 判断地址是否为IPV4地址
     */
    public static boolean IsIpv4(String ipv4) {
        if (ipv4 == null || ipv4.length() == 0) {
            return false;//字符串为空或者空串
        }
        String[] parts = ipv4.split("\\.");//因为java doc里已经说明, split的参数是reg, 即正则表达式, 如果用"|"分割, 则需使用"\\|"
        if (parts.length != 4) {
            return false;//分割开的数组根本就不是4个数字
        }
        for (String part : parts) {
            try {
                int n = Integer.parseInt(part);
                if (n < 0 || n > 255) {
                    return false;//数字不在正确范围内
                }
            } catch (NumberFormatException e) {
                return false;//转换数字不正确
            }
        }
        return true;
    }
}

(10)ToastUtil.java

import android.content.Context;
import android.widget.Toast;

public class ToastUtil {


    private static Toast mToast = null;

    /**
     * Toast方法
     *
     * @param text    需要展示的文本
     * @param context 所需上下文
     */
    public static void showToast(Context context, String text) {
        if (text != null) {
            if (mToast == null) {
                mToast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
            } else {
                mToast.setText(text);
                mToast.setDuration(Toast.LENGTH_SHORT);
            }
            mToast.show();
        }
    }

}

3.权限及声明

 <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"/>
<!--service部分-->
     <service android:name="com.test.test.LocalService"/>

代码到此为止了,功能比较简单。有什么疑问欢迎留言评论

版权声明:欢迎转载,请注明来源。

相关文章推荐

Android 使用Socket实现服务器与手机客户端的长连接四:使用回调函数与Service调用

1、改写原来客户端连接封装类,添加监听/** * @描述 使用socket实现长连接 * @项目名称 App_Chat * @包名 com.android.chat.utils * @类名 T...
  • lovoo
  • lovoo
  • 2016年06月27日 22:26
  • 2222

android--基于android平台socket服务器端实例

socket相关知识 1.什么是socket   所谓socket通常也称作"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。 以J2SDK-1.3为例,Socket和Server...

Android端与服务端基于TCP/IP协议的Socket通讯

http://blog.csdn.net/ryantang03/article/details/8274517 什么是TCP/IP协议? 百度百科的解释:Transmission Contr...

Android中使用Socket来实现服务器端和客户端,进行数据通信(使用原生Socket)

1、服务器端的实现 服务器端需要通过ServerSocket来创建一个ServerSocket服务对象,然后通过accept()方法Socket对象获得来监听连接上来的客户端(这个方法是阻塞的),最后...

17.app后端如何保证通讯安全--aes对称加密

在上文《16.app后端如何保证通讯安全--url签名》提到,url签名有两个缺点,这两个缺点,如果使用对称加密方法的话,则完全可以避免这两个缺点。在本文中,会介绍对称加密的具体原理,和详细的方案,使...
  • newjueqi
  • newjueqi
  • 2015年03月10日 18:09
  • 26919

客户端与服务器通信中的安全使者——AppSecret

作为一个移动互联网App,天生是需要和服务器通信的。那么,服务器如何识别客户端的身份?我们如何保证数据传输过程中的安全性?要靠两个东西:使用AppKey做身份识别,使用AppSecret校验数据。 ...

Android 使用Socket实现服务器与手机客户端的长连接二:多Client对一Server聊天

一、分析:1、修改原来的服务端,因为is.read(buffer)是阻塞式读取,所以必须把其抽取出来放置在新的子线程里。 不知大家还记不记得多线程下载的原理也是这样,开个主线程,其它的分段读取又都放...
  • lovoo
  • lovoo
  • 2016年06月26日 22:07
  • 2647

Android中使用Socket来实现服务器端和客户端,进行数据通信(使用原生Socket)

1、服务器端的实现 服务器端需要通过ServerSocket来创建一个ServerSocket服务对象,然后通过accept()方法Socket对象获得来监听连接上来的客户端(这个方法是阻塞的),最后...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android端基于socket的局域网内服务器与客户端加密通信
举报原因:
原因补充:

(最多只允许输入30个字)