之前做了一个安卓和设备通讯的 Socket 封装模块,用于和设备进行数据交流,极大地解决了旧代码的复杂与混乱,并且提供了扩展性。接下来我会分好几篇博客慢慢介绍这个通讯模块的各个部分,一步一步的将想要的设计,实现成详细的功能!
下面先简略介绍下 Socket 的运用。
文档准备
Java 中的 socket 代码在 java.net 包下,能够在安卓官方文档下看看,不过是英文的:
developer.android.google.cn/reference/k…
developer.android.google.cn/reference/k…
客户端运用
这儿先简略地介绍下 Socket 客户端的用法,后面封装,毕竟和设备衔接就靠客户端了。
简略用法
public void onClick(View view){
new Thread(){
@Override
public void run() {
super.run();
try {
//1.创立监听指定服务器地址以及指定服务器监听的端口号
Socket socket = new Socket("111.111.11.11", 12306);//111.111.11.11为我这个本机的IP地址,端口号为12306.
//2.拿到客户端的socket对象的输出流发送给服务器数据
OutputStream os = socket.getOutputStream();
//写入要发送给服务器的数据
os.write(et.getText().toString().getBytes());
os.flush();
socket.shutdownOutput();
//拿到socket的输入流,这儿存储的是服务器回来的数据
InputStream is = socket.getInputStream();
//解析服务器回来的数据
InputStreamReader reader = new InputStreamReader(is);
BufferedReader bufReader = new BufferedReader(reader);
String s = null;
final StringBuffer sb = new StringBuffer();
while((s = bufReader.readLine()) != null){
sb.append(s);
}
runOnUiThread(new Runnable() {
@Override
public void run() {
tv.setText(sb.toString());
}
});
//3、封闭IO资源(注:实际开发中需要放到finally中)
bufReader.close();
reader.close();
is.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
简略封装
学完 Socket 地简略用法,下面我们把它封装到 Service 里边去。下面是简化的代码,只说 Socket 衔接和接纳,其他东西在后续内容里边慢慢说:
public class ConnectService extends Service {
/** Socket相关,IP及端口号 **/
private String ip = "192.168.1.110";
private int port = 2050;
private int wait = 5000;
private Socket mSocket;
private Thread rxThread;
//初始化衔接
public void setUpConnection() throws IOException {
//封闭已有 socket
stopExistSocket();
//创立新的 socket
createSocket();
//发动接纳线程
startRxThread();
}
private void stopExistSocket() throws IOException {
if (mSocket != null) {
try {
mSocket.close();
mSocket = null;
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
}
private void createSocket() throws IOException {
SocketAddress sa = new InetSocketAddress(ip, port);
mSocket = new Socket();
try{
//设置信息及超时时间
mSocket.connect(sa, wait);
boolean isConnect = mSocket.isConnected();
mSocket.setKeepAlive(isConnect);
} catch(IOException e) {
mSocket = null;
throw e;
}
}
private void startRxThread() {
if (rxThread == null || !rxThread.isAlive()) {
rxThread = initReceiveThread();
rxThread.start();
}
}
//接受线程
private Thread initReceiveThread() {
return new Thread(new Runnable() {
@SuppressWarnings("ResultOfMethodCallIgnored")
@Override
public void run() {
try {
InputStream is;
while (mSocket != null) {
is = mSocket.getInputStream();
byte[] ackbuf = new byte[4]; //消息号
int ackrs = is.read(ackbuf, 0, 4);
if (ackrs < 0) {
Thread.sleep(1000);
continue;
}
//TODO 自行处理数据
...
}
}catch(IOException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
});
}
}
简略讲讲
实际这儿就三步,封闭已有 socket、创立新的 socket、发动接纳线程,都很简略。假如说有什么缺点的话,就是没有合理的封闭流吧,有时间我再改改!
服务端代码
和设备衔接用不到 Socket 服务端,所以这儿我就写个简略的比如吧!封装了一个模仿的服务端,一看就懂:
public class SimulateUtil {
public static class SocketServer extends Thread {
private Socket remotePeer;
private SocketServer(Socket remotePeer) {
this.remotePeer = remotePeer;
}
public void run() {
try {
InputStream is = null;
while(remotePeer!= null) {
isHxz = remotePeer.getInputStream();
//写的很大,能够写成常量
byte[] ackbuf = new byte[2560];
int len = is.read(ackbuf, 0, 2560);
if (len <= 0) {
Thread.sleep(1000);
continue;
}
//假装过一会回来数据
Thread.sleep(1000L + ((int) (Math.random() * 10)) * 100L);
remotePeer.getOutputStream().write("hey boy!".getBytes());
}
} catch(IOException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
}
/**
* 发动模仿进程
*/
public static void startSimulate() {
new Thread(() -> {
try {
ServerSocket serverSocket = new ServerSocket(54321);
while (true) {
Socket remotePeer = serverSocket.accept();
new SocketServer(remotePeer).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
下面是运用方法,application 中发动就行:
SimulateUtil.startSimulate();
留意点:
-
这儿的 IP 是本地地址(127.0.0.1)
-
端口号我们设置的 54321
-
封闭流什么的,能够参考下下面代码:
@Override public void run() { InputStreamReader reader = null; BufferedReader bufReader = null; OutputStream os = null; try { reader = new InputStreamReader(socket.getInputStream()); bufReader = new BufferedReader(reader); String s = null; StringBuffer sb = new StringBuffer(); while((s = bufReader.readLine()) != null){ sb.append(s); } System.out.println("服务器:"+sb.toString()); //封闭输入流 socket.shutdownInput(); //回来给客户端数据 os = socket.getOutputStream(); os.write(("我是服务端,客户端发给我的数据就是:"+sb.toString()).getBytes()); os.flush(); socket.shutdownOutput(); } catch (IOException e2) { e2.printStackTrace(); } finally{//封闭IO资源 if(reader != null){ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } if(bufReader != null){ try { bufReader.close(); } catch (IOException e) { e.printStackTrace(); } } if(os != null){ try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } }
结语
好了,这儿简略讲了一下 socket 的运用,用的都是 TCP 衔接,由于这儿是我写的《自定义安卓 socket 通讯模块系列》的一部分,所以更多的偏向了详细的运用,假如读者想要更多的了解 socket 的运用,能够参考下面的文章,我觉得写的非常好:
www.jianshu.com/p/fb4dfab4e…
别的,假如读者想继续了解我的《自定义安卓 socket 通讯模块系列》文章,能够点击链接跳转检查哦!
end