关于网络通信就一句话:一切通信皆socket。socket分为阻塞和非阻塞,服务端多为阻塞式,客户端多为非阻塞式。
非阻塞式主要开了两个线程,一个线程(ReadThread)专门读取服务端返回,一个线程(WriteThread)专门读取往服务器写消息。这个类的代码如下:
//消息发送线程
class SendThead extends Thread {
String messag;
//传入要发送的消息
public void setMessag(String messag) {
this.messag = messag;
}
@Override
public void run() {
while (true) {
if (messag != null) {
System.out.println("发送内容为:" + messag);
try {
writer.write(messag);
writer.flush();
isSend = true;
} catch (IOException e) {
e.printStackTrace();
isSend = false;
} finally {
handler.sendEmptyMessage(404);
break;
}
}
}
}
}
//消息读取线程
class ReadThread extends Thread {
@Override
public void run() {
while (true) {
if (isSend) {
//如果发送成功才读取消息
try {
String line;
while ((line = reader.readLine()) != null) {
builder.append(line + "\r\n");
reader.read();
isRead = true;
}
} catch (IOException e) {
e.printStackTrace();
isRead = false;
} finally {
System.out.println("test 服务返回内容:" + builder.toString());
handler.sendEmptyMessage(200);
break;
}
}
}
}
}
以上两个类都在测试的activity中,下面是activity的主要代码
public class TestActivity extends AppCompatActivity {
private EditText etInput;
private TextView tvContent;
private BufferedWriter writer;
private BufferedReader reader;
private SendThead sendThead;
boolean isSend;//标记消息是否发送成功
boolean isRead;//标记消息是否读取成功
private Socket clientSocket;
StringBuilder builder = new StringBuilder();
private ReadThread readThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
etInput = ((EditText) findViewById(R.id.et_input));
tvContent = ((TextView) findViewById(R.id.tv_content));
//开启读写线程
sendThead = new SendThead();
sendThead.start();
readThread = new ReadThread();
readThread.start();
//创建socket连接
new Thread(new Runnable() {
@Override
public void run() {
try {
clientSocket = new Socket(Constant.RTU_IP, Constant.RTU_PORT);
InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream();
writer = new BufferedWriter(new OutputStreamWriter(outputStream));
reader = new BufferedReader(new InputStreamReader(inputStream));
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 404:
ComUtils.showToast(TestActivity.this, isSend ? "发送成功" : "发送失败");
break;
case 200:
String result = builder.toString();
tvContent.setText(isRead ? result : "读取失败");
break;
}
}
};
//点击按钮发送消息
public void sendMessage(View view) throws InterruptedException {
String input = etInput.getText().toString().trim();
//如果连接成功就发送消息
boolean alive = readThread.isAlive();
System.out.println("线程是否开启:" + alive + "==");
if (clientSocket.isConnected()) {
sendThead.setMessag(input);
} else {
ComUtils.showToast(this, "请稍后发送,socket还在连接中");
//也可以将消息存到未发送的消息集合中去
}
}
最后运行效果:
最后是关闭socket的方法:
@Override
protected void onDestroy() {
super.onDestroy();
if (clientSocket != null && !clientSocket.isClosed()) {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
//那些读写的流不要去管,调用close方法,socket会去关闭读写流的,见下面google文档截图
//Closing this socket will also close the socket's InputStream and OutputStream.
clientSocket = null;
}
}
}
anroid和硬件交互常常用到socket,由于原生socket写起来和用起来非常麻烦,目前封装比较好的socket通信框架是mina和netty,这两个框架的作者是同一个人,使用起来非常方便简化。