检查设备自身与某个网络地址的连通性用到了InetAddress工具,这是对网络地址的一个封装。下面介绍该工具的主要方法说明。
getByName:根据主机IP或主机名称获取InetAddress对象。
getHostAddress:获取主机的IP地址。
getHostName:获取主机的名称。
isReachable:判断该地址是否可到达,即是否连通。
public void onClick(View v) {
if (v.getId() == R.id.btn_host_name) {
// 点击了“检查主机名”按钮
// 启动主机检查线程
new CheckThread(et_host_name.getText().toString()).start();
}
}
// 创建一个检查结果的接收处理器
private Handler mHandler = new Handler() {
// 在收到结果消息时触发
public void handleMessage(Message msg) {
tv_host_name.setText("主机检查结果如下:\n" + msg.obj);
}
};
// 定义一个主机检查线程
private class CheckThread extends Thread {
private String mHostName; // 主机名称
public CheckThread(String host_name) {
mHostName = host_name;
}
public void run() {
// 获得一个默认的消息对象
Message message = Message.obtain();
try {
// 根据主机名称获得主机名称对象
InetAddress host = InetAddress.getByName(mHostName);
// 检查该主机在规定时间内能否连上
boolean isReachable = host.isReachable(5000);
String desc = (isReachable) ? "可以连接" : "无法连接";
if (isReachable) {
// 可以连接
desc = String.format("%s\n主机名为%s\n主机地址为%s",
desc, host.getHostName(), host.getHostAddress());
}
message.what = 0; // 消息类型
message.obj = desc; // 消息描述
} catch (Exception e) {
e.printStackTrace();
message.what = -1; // 消息类型
message.obj = e.getMessage(); // 消息描述
}
// 向接收处理器发送检查结果消息
mHandler.sendMessage(message);
}
}
检测域名的连通性结果图
检测IP的连通性结果图
计算机网络有一个大名鼎鼎的TCP/IP协议,TCP/IP是一个协议组,分为3个层次:
Socket属于传输层的技术, API实现TCP协议后即可用于HTTP通信,实现UDP协议后即可用于FTP通信,当然也可以直接在底层进行点对点通信。
Android的Socket编程主要使用Socket和ServerSocket两个类:
Socket是最常用的工具,客户端和服务端都要用到,描述了两边对套接字(Socket)处理的一般行为。主要方法如下:
ServerSocket仅用于服务端,在运行时不停地侦听指定端口。主要方法如下:
举个Socket通信的案例,详细步骤说明如下:
(1)首先在客户端与服务端之间建立Socket连接。
(2)然后在Activity中启动Socket连接的线程,等待界面向Socket服务器发送消息,并准备接收消息。
(3)最后启动Socket服务器(其实一开始就要启动,这样App运行时才能马上连上后端服务器)。
下面是在客户端与服务端之间建立Socket连接的详细代码:
public class MessageTransmit implements Runnable {
// 以下为Socket服务器的ip和端口,根据实际情况修改
private static final String SOCKET_IP = "192.168.0.212";
private static final int SOCKET_PORT = 51000;
private BufferedReader mReader = null; // 声明一个缓存读取器对象
private OutputStream mWriter = null; // 声明一个输出流对象
@Override
public void run() {
// 创建一个套接字对象
Socket socket = new Socket();
try {
// 命令套接字连接指定地址的指定端口
socket.connect(new InetSocketAddress(SOCKET_IP, SOCKET_PORT), 3000);
// 根据套接字的输入流,构建缓存读取器
mReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 获得套接字的输出流
mWriter = socket.getOutputStream();
// 启动一条子线程来读取服务器的返回数据
new RecvThread().start();
// 为当前线程初始化消息队列
Looper.prepare();
// 让线程的消息队列开始运行,之后就可以接收消息了
Looper.loop();
} catch (Exception e) {
e.printStackTrace();
}
}
// 创建一个发送处理器对象,让App向后台服务器发送消息
public Handler mSendHandler = new Handler() {
// 在收到消息时触发
public void handleMessage(Message msg) {
// 换行符相当于回车键,表示我写好了发出去吧
String send_msg = msg.obj.toString() + "\n";
try {
// 往输出流对象中写入数据
mWriter.write(send_msg.getBytes("utf8"));
} catch (Exception e) {
e.printStackTrace();
}
}
};
// 定义消息接收子线程,让App从后台服务器接收消息
private class RecvThread extends Thread {
@Override
public void run() {
try {
String content;
// 读取到来自服务器的数据
while ((content = mReader.readLine()) != null) {
// 获得一个默认的消息对象
Message msg = Message.obtain();
msg.obj = content; // 消息描述
// 通知SocketActivity收到消息
SocketActivity.mHandler.sendMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
下面是等待界面向Socket服务器发送消息,并准备接收消息的页面代码:
public class SocketActivity extends AppCompatActivity implements OnClickListener {
private EditText et_socket;
private static TextView tv_socket;
private MessageTransmit mTransmit; // 声明一个消息传输对象
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_socket);
et_socket = findViewById(R.id.et_socket);
tv_socket = findViewById(R.id.tv_socket);
findViewById(R.id.btn_socket).setOnClickListener(this);
mTransmit = new MessageTransmit(); // 创建一个消息传输
new Thread(mTransmit).start(); // 启动消息传输线程
}
public void onClick(View v) {
if (v.getId() == R.id.btn_socket) {
// 获得一个默认的消息对象
Message msg = Message.obtain();
msg.obj = et_socket.getText().toString(); // 消息内容
// 通过消息线程的发送处理器,向后端发送消息
mTransmit.mSendHandler.sendMessage(msg);
}
}
// 创建一个主线程的接收处理器,专门处理服务器发来的消息
public static Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (tv_socket != null) {
// 拼接服务器的应答字符串
String desc = String.format("%s 收到服务器的应答消息:%s",
DateUtil.getNowTime(), msg.obj.toString());
tv_socket.setText(desc);
}
}
};
}
Socket通信的实现效果:
Socket消息发送前的界面
Socket消息发送后的界面