(3)客户端主界面 Function_Socket_Client.java
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125import
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(
"尝试发送数据到
"+ 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
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34import
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
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45import
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
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57import
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 +
"
");
//由于socket使用缓冲区进行读写数据,因此使用
用于表明数据已写完.不加这个会导致数据无法发送
EventBus.getDefault().post(ConstantUtil.CODE_SUCCESS);
writer.flush();
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
}
(7)AESUtil.java
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142import
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 +
"
content="+ 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 +
"
content="+ 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)ConstantUti.java
?
1 2 3 4 5 6 7 8 9 10 11/**
* 常量类
*/
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
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71import
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
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27import
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.权限及声明
?
1 2 3 4 5<
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"/>