文章目录

  • manifests
    • AndroidManifest.xml
  • java
    • Activity
      • BaseEventAcitivity
      • Function_Socket_Server
    • SQL
    • Thread
      • ListenThread
      • ServerHandleSocketThread
    • Util
      • AESUtil
      • ClientSocket
      • ConstantUtil
      • RSAUtil
      • SRConstantsUtil
      • ToolUtil
  • res
    • layout
      • funtion_socket_server.xml
    • values
      • styles.xml


这是服务器端,整个通信软件客户端,服务器端源码包已经上传到我的资源。

manifests

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>                                                                                            

java

Activity

BaseEventAcitivity

package com.example.socketserver.Activity;import android.os.Bundle;import android.view.Window;import androidx.appcompat.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);        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);        getIntentData();        setContentView(getLayoutResId());        ButterKnife.bind(this);// 相当于 activity.subtitle = (TextView) activity.findViewById(R.id.subtitle);        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();}

Function_Socket_Server

package com.example.socketserver.Activity;import android.app.ProgressDialog;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.View;import android.widget.TextView;import android.widget.Toast;import com.example.socketserver.Thread.ListenThread;import com.example.socketserver.Util.AESUtil;import com.example.socketserver.Util.ConstantUtil;import com.example.socketserver.Service.LocalService;import com.example.socketserver.R;import com.example.socketserver.Util.ToolUtil;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;    @BindView(R.id.edtTxt_server_Content)    TextView edtTxt_server_Content;    @BindView(R.id.edtTxt_server_clientAddress)    TextView edtTxt_server_clientAddress;    @Override    protected int getLayoutResId() {        return R.layout.function_socket_server;    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        new ListenThread(ConstantUtil.port,Function_Socket_Server.this).start();    }    @Override    protected void init() {        Log.d("Function_Socket_Server","init");        tv_localAddress.setText(ToolUtil.getHostIP());//获取本机局域网ip地址    }    @OnClick({R.id.btn_startListener, R.id.btn_stopListener, R.id.btn_getUser,R.id.btn_server_encryptAndSend})    public void onClick(View v) {        switch (v.getId()) {            case R.id.btn_startListener://启动监听                break;            case R.id.btn_stopListener://停止监听                break;            case R.id.btn_getUser://刷新连接到此设备的IP并清空之前接收到的数据                ArrayList connectedIP = getConnectedIP();                StringBuilder resultList = new StringBuilder();                for (String ip : connectedIP) {                    resultList.append(ip);                    resultList.append("\n");                }                Toast.makeText(Function_Socket_Server.this, "连接到手机上的Ip是"+ resultList.toString(), Toast.LENGTH_LONG).show();                tv_decryptContent.setText("");                tv_receivedContent.setText("");                break;            case R.id.btn_server_encryptAndSend:                Toast.makeText(Function_Socket_Server.this, "未实现功能", Toast.LENGTH_SHORT).show();                break;        }    }    //订阅事件处理,处理 ListenThread 的 EventBus.getDefault().post(str);    @Subscribe(threadMode = ThreadMode.MAIN)//在ui线程执行    public void getData(String data) {        //dismissProgressDialog();        switch (data) {            default:                tv_receivedContent.append(data+"\n");                tv_decryptContent.append(AESUtil.decrypt(ConstantUtil.password, data)+"\n");                break;        }    }    /**     * 获取连接到本机热点上的手机ip     */    private ArrayList getConnectedIP() {        ArrayList 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;    }}

SQL

SQLiteHelper

package com.example.socketserver.SQL;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;public class SQLiteHelper extends SQLiteOpenHelper {    //构造socket的数据库    public SQLiteHelper(Context context) {        super(context, "socket.db", null, 1);    }    @Override    public void onCreate(SQLiteDatabase db) {        //创建一个名字为 information,3列的表格        //列:1: _id,2: USERNAME,3: PASSWORD        db.execSQL("CREATE TABLE information(_id INTEGER PRIMARY KEY AUTOINCREMENT," +                "USERNAME VARCHAR(20),PASSWORD VARCHAR(30),PRIVATEKEY VARCHAR(1250),PUBLICKEY VARCHAR(350))");//,LATESTIP VARCHAR(15)    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

Thread

ListenThread

package com.example.socketserver.Thread;import android.content.Context;import android.util.Log;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;/** * 监听线程 */public class ListenThread extends Thread {    private ServerSocket serverSocket;    private Context context;    //构造函数,传递,端口,上下文    public ListenThread(int port, Context context) {        try {            serverSocket = new ServerSocket(port);//服务器端:创建绑定到指定 端口 的服务器套接字        } catch (IOException e) {            e.printStackTrace();        }        this.context = context;    }    @Override    public void run() {        Log.d("ListenThread","run");        while (true) {//不断得循环等待连接,读取数据            try {                if (serverSocket != null) {                    Socket socket = serverSocket.accept();//调用accept()方法 等待客户连接                    final String address = socket.getRemoteSocketAddress().toString();//获取发送客户端的地址                    Log.d("ListenThread","new clients socket address:"+address);                    //每一个socket单独开启一个线程                    ServerHandleSocketThread serverThread = new ServerHandleSocketThread(socket,context);                    serverThread.start();                }            }            catch (IOException e) {                e.printStackTrace();            }        }    }}

ServerHandleSocketThread

package com.example.socketserver.Thread;import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.os.Build;import android.util.Log;import androidx.annotation.RequiresApi;import com.example.socketserver.SQL.SQLiteHelper;import com.example.socketserver.Util.AESUtil;import com.example.socketserver.Util.ClientSocket;import com.example.socketserver.Util.ConstantUtil;import com.example.socketserver.Util.RSAUtil;import com.example.socketserver.Util.SRConstantsUtil;import org.greenrobot.eventbus.EventBus;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.net.Socket;import java.security.NoSuchAlgorithmException;import java.util.Iterator;import java.util.Set;class ServerHandleSocketThread extends Thread{    private Socket socket;    private Context context;    private boolean exit = false;    //在构造中得到要单独会话的socket    public ServerHandleSocketThread(Socket socket, Context context) {        this.socket = socket;        this.context = context;    }    @RequiresApi(api = Build.VERSION_CODES.O)    @Override    public void run() {        super.run();        if(!exit)        while(true){            if(exit == true)break;            try {                InputStream inputStream = socket.getInputStream();//实现客户端和服务器端在线程上对话, 读取输入流                if (inputStream != null) {                    //读取接收到的数据                    BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));                    String dataPacket = in.readLine();//读一行数据                    //发送过来的数据不为空,判断数据内容                    if (dataPacket != null) {                        String clientData = AESUtil.decrypt(ConstantUtil.password, dataPacket);                        int cmdBeginIndex1=clientData.indexOf(":")+1;                        int cmdEndIndex1 = clientData.indexOf("}");                        String cmd=clientData.substring(cmdBeginIndex1,cmdEndIndex1);                        //登录,                        if (cmd.equals("login")) {                            Log.d("HandleSocketThread", "handle login");                            //获取登录的用户名                            int userNameBeginIndex = clientData.indexOf(":",cmdBeginIndex1) + 1;                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);                            String username = clientData.substring(userNameBeginIndex, userNameEndIndex);                            //获取登录的密码                            int passwordBeginIndex = clientData.indexOf(":", userNameBeginIndex) + 1;                            int passwordEndIndex = clientData.indexOf("}", userNameEndIndex + 1);                            String password = clientData.substring(passwordBeginIndex, passwordEndIndex);                            SQLiteDatabase db;                            ContentValues values;                            SQLiteHelper helper = new SQLiteHelper(context);                            db = helper.getReadableDatabase();                            //执行查询的SQL语句,查询账号,密码是否存在数据库中                            //密码加密加密存储,所以得把得到的密码加密查询                            Cursor cursor = db.rawQuery("select * from information where USERNAME=? and PASSWORD=?",                                    new String[]{username, AESUtil.encrypt(ConstantUtil.password, password)});                            //查无此数据,返回                            if (cursor.getCount() == 0) {                                Log.d("HandleSocketThread", "login,无此用户数据");                                //返回登录失败信息                                writeResponse(socket, SRConstantsUtil.LOGIN_FAILED);                                socket.close();                                exit = true;                            }                            //有此数据,准许登录                            else if(cursor.getCount()!=0){                                cursor.moveToFirst();                                Log.d("HandleSocketThread ", "Login success "+"账号:" + cursor.getString(1) + "密码:" + cursor.getString(2));                                Set keyset = ClientSocket.keySet();                                Iterator it = keyset.iterator();                                while (it.hasNext()) {                                    String username1 = it.next();                                    if (username1.equals(username)) {                                        //返回该账号已经登录信息                                        writeResponse(socket,SRConstantsUtil.LOGIN_ALREADY);                                        cursor.close();                                        db.close();                                        return;                                    }                                }                                ClientSocket.put(username,socket);                                Log.d("HandleSocketThread","add socket,clientSocketSize:"+String.valueOf(ClientSocket.size()));                                //返回登录成功信息                                writeResponse(socket,SRConstantsUtil.LOGIN_SUCCESS);                            }                            cursor.close();                            db.close();                        }                        //连接通信,保持socket存在获取客户聊天使用的socket                        else if(cmd.equals("connect")){                            Log.d("HandleSocketThread", "connect ");                            //获取登录的用户名                            int userNameBeginIndex = clientData.indexOf(":",cmdBeginIndex1) + 1;                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);                            String username = clientData.substring(userNameBeginIndex, userNameEndIndex);                            //返回连接成功信息                            writeResponse(socket,SRConstantsUtil.CONNECTSUCCESS);                        }                        //获得好友公钥                        else if(cmd.equals("addFriend")){                            //获取添加的好友的用户名                            int userNameBeginIndex = clientData.indexOf(":",cmdBeginIndex1) + 1;                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);                            String frinedUsername = clientData.substring(userNameBeginIndex, userNameEndIndex);                            //查询数据库有无此数用户名                            SQLiteDatabase db;                            ContentValues values;                            SQLiteHelper helper = new SQLiteHelper(context);                            db = helper.getReadableDatabase();                            //执行查询的SQL语句                            Cursor cursor = db.rawQuery("select * from information where USERNAME=? ",                                    new String[]{frinedUsername});                            //查无此数据,存储返回                            if (cursor.getCount() == 0) {                                Log.d("HandleSocketThread", "no this frinedUsername ");                                //返回获取公钥错误                                writeResponse(socket,SRConstantsUtil.NOFRIENDACCOUNT);                            }                            else {                                cursor.moveToFirst();//这句话一定要有,不然无法选中第一条!!!!!                                String publicKey = cursor.getString(4);                                if(publicKey != null){                                    Log.d("ServerThread", "发送公钥");                                    String publicKeyPacket = "{response:sendPublicKey}{key:"+publicKey+"}";                                    writeResponse(socket,publicKeyPacket);                                }                            }                            cursor.close();                            db.close();                        }                        //自己私钥                        else if(cmd.equals("getPrivateKey")){                            //{cmd:getPrivateKey}{username:"+username+"}"                            //获取登录的用户名                            int userNameBeginIndex = clientData.indexOf(":",cmdBeginIndex1) + 1;                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);                            String username = clientData.substring(userNameBeginIndex, userNameEndIndex);                            //查询数据库有无此数用户名                            SQLiteDatabase db;                            ContentValues values;                            SQLiteHelper helper = new SQLiteHelper(context);                            db = helper.getReadableDatabase();                            //执行查询的SQL语句                            Cursor cursor = db.rawQuery("select * from information where USERNAME=? ",                                    new String[]{username});                            //查无此数据,存储返回                            if (cursor.getCount() == 0) {                                Log.d("HandleSocketThread", "get public key error");                                //返回获取公钥错误                                writeResponse(socket,SRConstantsUtil.GETPUBLICKEYERROR);                            }                            else {                                cursor.moveToFirst();//这句话一定要有,不然无法选中第一条!!!!!                                String privateKey = cursor.getString(3);                                Log.d("ServerThread", "发送私钥");                                //返回注册失败信息                                String publicKeyPacket = "{response:sendPrivateKey}{key:"+privateKey+"}";                                writeResponse(socket,publicKeyPacket);                            }                            cursor.close();                            db.close();                        }                        //发送消息,                        else if (cmd.equals("sendMsg")) {                            Log.d("HandleSocketThread", "handle sendmsg");                            boolean recIsOnline = false;                            //提取接收者账号                            //{cmd:sendMsg}{receiverAccount:123}{msg:xxxx}{sender:xxx}                            int recBeginIndex=clientData.indexOf(":",cmdBeginIndex1)+1;                            int recIndex=clientData.indexOf("}", recBeginIndex);                            String recAccount=clientData.substring(recBeginIndex,recIndex);                            //根据接收者账号 遍历寻找是否在线                            //判断登录存储的map中有 数据接收者账号                            //有就从map中找到 相应接收者账号的socket,提取cilentData中的msg,并且发送消息出去给相应客户                            //返回 发送者发送成功的消息,关闭发送者 发送数据的socket                            Set keyset = ClientSocket.keySet();                            Iterator it = keyset.iterator();                            while (it.hasNext()){                                String username = it.next();                                if(username.equals(recAccount))                                {                                    Log.d("HandleSocketThread","handle sendmsg,search and get recAccount:"+username);                                    Log.d("HandleSocketThread","handle sendmsg,receiver is online ");                                    recIsOnline = true;                                    int msgBeginIndex=clientData.indexOf(":",recBeginIndex)+1;                                    int msgIndex=clientData.indexOf("}", recIndex+1);                                    String msg=clientData.substring(msgBeginIndex,msgIndex);                                    int nextBeginIndex=clientData.indexOf("{",msgBeginIndex);                                    int sendBeginIndex=clientData.indexOf(":",nextBeginIndex)+1;                                    int sendIndex=clientData.indexOf("}", sendBeginIndex);                                    String sendAccount=clientData.substring(sendBeginIndex,sendIndex);                                    Log.d("HandleSocketThread","handle sendmsg,sendAccount is "+sendAccount+",now send "+msg+" to "+username);                                    String msgPacket = "{response:transmit}{sender:"+sendAccount+"}{msg:"+msg+"}";                                    //根据keyset 找到 对应接收者的socket                                    Socket socket1 = ClientSocket.get(username);                                    writeResponse(socket1,msgPacket);                                    Log.d("HandleSocketThread","handle sendmsg,msg has sent");                                    //返回发送成功信息                                    writeResponse(socket,SRConstantsUtil.MSGSEND_SUCCESS);                                    //找到发送对象并且发送完毕,退出本次发送循环                                    break;                                }                            }                            //不在线,在线标志位 由遍历过程 改变                            if(recIsOnline == false){                                Log.d("HandleSocketThread","handle sendmsg,receiver isn't online ");                                //返回接收者不在线信息                                writeResponse(socket,SRConstantsUtil.MSGSEND_FAILED_NOT_ONLINE);                            }                            exit = true;                        }                        //注册,关闭socket                        else if (cmd.equals("register")) {                            Log.d("HandleSocketThread", "handle register");                            //获取注册的用户名                            int userNameBeginIndex = clientData.indexOf(":",cmdBeginIndex1) + 1;                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);                            String username = clientData.substring(userNameBeginIndex, userNameEndIndex);                            //获取注册的密码                            int passwordBeginIndex = clientData.indexOf(":", userNameBeginIndex) + 1;                            int passwordEndIndex = clientData.indexOf("}", userNameEndIndex + 1);                            String password = clientData.substring(passwordBeginIndex, passwordEndIndex);                            //查询数据库有无此数用户名                            SQLiteDatabase db;                            ContentValues values;                            SQLiteHelper helper = new SQLiteHelper(context);                            db = helper.getReadableDatabase();                            //执行查询的SQL语句                            Cursor cursor = db.rawQuery("select * from information where USERNAME=? ",                                    new String[]{username});                            //查无此数据,存储返回                            if (cursor.getCount() == 0) {                                Log.d("HandleSocketThread", "register,注册用户名无冲突");                                db = helper.getWritableDatabase();                                values = new ContentValues();//创建Contentvalues对象                                values.put("USERNAME", username);//将数据添加到ContentValues对象                                values.put("PASSWORD", AESUtil.encrypt(ConstantUtil.password, password));                                RSAUtil.genKeyPair();                                String publicKey = RSAUtil.getPublicKey();                                String privateKey = RSAUtil.getPrivateKey();                                values.put("PRIVATEKEY", privateKey);                                values.put("PUBLICKEY", publicKey);                                db.insert("information", null, values);                                Log.d("HandleSocketThread", "register,存储成功");                                //返回注册成功信息                                writeResponse(socket,SRConstantsUtil.REGISTER_SUCCESS);                            }                            else {                                Log.d("ServerThread", "注册用户名冲突");                                //返回注册失败信息                                writeResponse(socket,SRConstantsUtil.REGISTER_FAILED);                            }                            cursor.close();                            db.close();                            socket.close();                            exit = true;                        }                        //用户退出APP消息,关闭socket,删除相应的map中的socket                        else if(cmd.equals("exitApp")) {                            Log.d("HandleSocketThread", "handle exist");                            //{cmd:exitAPP}{username:123}                            int userNameBeginIndex=clientData.indexOf(":",cmdBeginIndex1)+1;                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);                            String username=clientData.substring(userNameBeginIndex,userNameEndIndex);                            ClientSocket.remove(username);                            Log.d("HandleSocketThread","handle exist,clientSocketSize:"+String.valueOf(ClientSocket.size()));                            //返回收到退出信息                            writeResponse(socket,SRConstantsUtil.EXISTAPPNORMAL);                            socket.close();                            exit = true;                        }                        else Log.d("HandleSocketThread","数据格式错误");                        EventBus.getDefault().post(dataPacket);//发布事件,把获取到的信息显示出来                    }                }            }            catch (IOException | NoSuchAlgorithmException e) {                e.printStackTrace();            }        }    }    private void writeResponse(Socket socket,String response) throws IOException {        OutputStream outputStream = socket.getOutputStream();        OutputStreamWriter opsw = new OutputStreamWriter(outputStream);//        BufferedWriter writer = new BufferedWriter(opsw);        writer.write(AESUtil.encrypt(ConstantUtil.password, response)+ "\r\n\r\n");//由于socket使用缓冲区进行读写数据,因此使用\r\n\r\n用于表明数据已写完.不加这个会导致数据无法发送        writer.flush();    }}

Util

AESUtil

package com.example.socketserver.Util;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;CFB(Cipher FeedBack Mode,加密反馈),不填充    /**     * 生成加密后的密钥     *     * @param password 密钥种子     * @return isSucceed     */    private static SecretKeySpec createKey(String password) {        byte[] data = null;        if (password == null) {            password = "";        }        StringBuilder sb = new StringBuilder(32);//32位容量的字符串        sb.append(password);//字符串追加密码        while (sb.length() < 32) {            sb.append("0");//少于32位,追加‘0’        }        if (sb.length() > 32) {            //setLength(newLength)            //如果 newLength 参数小于当前长度,则长度将更改为指定的长度。            //如果 newLength 参数大于或等于当前长度,则将追加有效的 null 字符 ('u0000'),使长度满足 newLength 参数。            sb.setLength(32);        }        try {            data = sb.toString().getBytes("UTF-8");//得到 使用UTF-8编码表 的一个系统默认的编码格式的 字节数组        } catch (UnsupportedEncodingException e) {            e.printStackTrace();        }        return new SecretKeySpec(data, "AES");//根据32字节的数据,生成一个AES算法生成的密钥    }    // /** 加密字节数据 **/    private static byte[] encrypt(byte[] content, String password) {        try {            SecretKeySpec key = createKey(password);//根据密钥种子生成密钥            System.out.println(key);            Cipher cipher = Cipher.getInstance(CipherMode);            //初始化Cipher,mode指定是加密还是解密,key为公钥或密钥;ENCRYPT_MODE加密模式,            // 实例化IvParameterSpec对象,使用指定的初始化向量            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(                    new byte[cipher.getBlockSize()]));            //使用CFB加密CFB(Cipher FeedBack Mode,加密反馈)、不填充的方式            //init为 加密形式            //返回btye[]数组            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;//byte字节数组        try {            data = content.getBytes("UTF-8");        } catch (Exception e) {            e.printStackTrace();        }        data = encrypt(data, password);//加密字节数据        String result = byte2hex(data);//字节转hex        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;    }}

ClientSocket

package com.example.socketserver.Util;import java.net.Socket;import java.util.HashMap;import java.util.Set;public class ClientSocket {    private static HashMap clients = new HashMap();// 创建一个集合存放所有的客户端 的用户名,和客户socket    public static void put(String username, Socket userSocket){        clients.put(username,userSocket);    }    public static int size() {        return clients.size();    }    public static Socket get(String username) {        return clients.get(username);    }    public static void remove(String username) {        clients.remove(username);    }    public static Set keySet() {        return clients.keySet();    }}

ConstantUtil

package com.example.socketserver.Util;/** * 常量类 */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 String CODE_TIMEOUT = "pzl0";//连接超时    public static final String CODE_SUCCESS = "pzl1";//连接成功    public static final String CODE_UNKNOWN_HOST = "pzl2";//错误-未知的host    public static final String SERVERIP = "SERVERIP";//服务器地址}

RSAUtil

package com.example.socketserver.Util;import android.os.Build;import androidx.annotation.RequiresApi;import java.util.Base64;import javax.crypto.Cipher;import java.security.KeyFactory;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import java.security.interfaces.RSAPrivateKey;import java.security.interfaces.RSAPublicKey;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;import java.util.HashMap;import java.util.Map;public class RSAUtil {    /**     * 密钥长度 于原文长度对应 以及越长速度越慢     */    private final static int KEY_SIZE = 1536;    private static final String CipherMode = "RSA";    /**     * 用于封装随机产生的公钥与私钥     */    private static Map keyMap = new HashMap();    //公钥    public static final String PUBLIC_KEY = "RSAPublicKey";    //私钥    public static final String PRIVATE_KEY = "RSAPrivateKey";    /**     * 随机生成密钥对     */    @RequiresApi(api = Build.VERSION_CODES.O)    public static void genKeyPair() throws NoSuchAlgorithmException {        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(CipherMode);        // 初始化密钥对生成器        keyPairGen.initialize(KEY_SIZE, new SecureRandom());        // 生成一个密钥对,保存在keyPair中        KeyPair keyPair = keyPairGen.generateKeyPair();        // 得到私钥        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();        // 得到公钥        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();        String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());        // 得到私钥字符串        String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());        // 将公钥和私钥保存到Map        //0表示公钥        keyMap.put(PUBLIC_KEY, publicKeyString);        //1表示私钥        keyMap.put(PRIVATE_KEY, privateKeyString);    }    public static String getPublicKey(){        return keyMap.get(PUBLIC_KEY);    }    public static String getPrivateKey(){        return keyMap.get(PRIVATE_KEY);    }    /**     * RSA公钥加密     *     * @param str       加密字符串     * @param publicKey 公钥     * @return 密文     * @throws Exception 加密过程中的异常信息     */    @RequiresApi(api = Build.VERSION_CODES.O)    public static String encrypt(String str, String publicKey) throws Exception {        //base64编码的公钥        byte[] decoded = Base64.getDecoder().decode(publicKey);        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(CipherMode).generatePublic(new X509EncodedKeySpec(decoded));        //RSA加密        Cipher cipher = Cipher.getInstance(CipherMode);        cipher.init(Cipher.ENCRYPT_MODE, pubKey);        String outStr = Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes("UTF-8")));        return outStr;    }    /**     * RSA私钥解密     *     * @param str        加密字符串     * @param privateKey 私钥     * @return 明文     * @throws Exception 解密过程中的异常信息     */    public static String decrypt(String str, String privateKey) throws Exception {        //64位解码加密后的字符串        byte[] inputByte = Base64.getDecoder().decode(str);        //base64编码的私钥        byte[] decoded = Base64.getDecoder().decode(privateKey);        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(CipherMode).generatePrivate(new PKCS8EncodedKeySpec(decoded));        //RSA解密        Cipher cipher = Cipher.getInstance(CipherMode);        cipher.init(Cipher.DECRYPT_MODE, priKey);        String outStr = new String(cipher.doFinal(inputByte));        return outStr;    }}

SRConstantsUtil

package com.example.socketserver.Util;public class SRConstantsUtil {    public static final String REGISTER_SUCCESS = "{response:register_success}";//注册成功    public static final String REGISTER_FAILED = "{response:register_failed}";//注册失败    public static final String LOGIN_SUCCESS = "{response:login_success}";//登录成功    public static final String LOGIN_FAILED = "{response:login_failed}";//登录识别    public static final String LOGIN_ALREADY = "{response:login_already}";//登录识别    public static final String MSGSEND_SUCCESS = "{response:send_msg_success}";//连接成功    public static final String MSGSEND_FAILED = "{response:send_msg_failed}";//连接成功    public static final String MSGSEND_FAILED_NOT_ONLINE = "{response:receiver_not_online}";//接收者不在线    public static final String MSGSEND_FAILED_NOT_EXIST = "{response:receiver_not_exist}";//接收者错误    public static final String EXISTAPPNORMAL = "{response:exist_normal}";//退出成功    public static final String EXISTAPPABNORMAL = "{response:exist_abnormal}";//退出错误    public static final String CONNECTSUCCESS = "{response:connect_success}";//连接成功    public static final String NOFRIENDACCOUNT = "{response:no_user_account}";//没有此好友用户    public static final String GETPUBLICKEYERROR = "{response:get_privateKey_error}";//获取公钥错误    //public static final String PRIVATEKEY = "{response:privateKey}{key:";//获取公钥错误}

ToolUtil

package com.example.socketserver.Util;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 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;    }}

res

layout

funtion_socket_server.xml

<?xml version="1.0" encoding="utf-8"?>                                                    

values

styles.xml

        

gradle与客户端一样

更多相关文章

  1. Android(安卓)JSON,Gson,fastjson实现比较
  2. ch020 Android(安卓)SQLite3(第二部分)
  3. ch020 Android(安卓)SQLite3(第二部分)
  4. Android漏洞——将Android恶意代码隐藏在图片中
  5. 第三课:android数据相关---文件
  6. Android(安卓)Media (Audio) Framework Analyse
  7. [Android(安卓)Develop_003]-Android(安卓)Database
  8. android中的数据库操作
  9. struts2服务端与android交互

随机推荐

  1. 让Android的输入框与文本框带滚动条Scrol
  2. android fragment学习5--fragment扩展 Ta
  3. Android中tools属性的使用
  4. Android 开发者该学点Linux 命令了
  5. Android startActivityForResult request
  6. android Gallery3D效果
  7. android中定制的dialog
  8. Android(安卓)Interface Definition Lang
  9. java中org.xml.sax不能读取xml回车换行的
  10. android之MultiAutoCompleteTextView