【Android开发艺术】Socket进程间通信
前言:
接下来大概很久都不会再写关于Android的文章了,毕竟要转去后端做开发了。这篇文章用来作为一个前后端的交接还是蛮不错的。毕竟Socket网络编程,平时都只是说说而已,不曾用过。许多时候,我写文章主要是用来巩固学习成果,比如今天做了什么,或者今天学了什么,或者之前学的东西快忘了赶紧记录下来。
正文:
一、关于socket可以看看这篇文章链接。
二、写个服务端App(Github代码提取点)
举例:客户端App发消息到服务端App、服务端App实时回复功能。
package haibo.com.socketservel.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
public class TCPServerService extends Service {
private boolean mIsServiceDestoryed = false;
private final String TAG = "TCPServerService";
private String[] mDefinedMsg = new String[]{
"你好啊,哈哈",
"请问你叫什么名字呀?",
"你是哥哥还是妹妹?",
"给你讲个笑话好不好"
};
public TCPServerService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG,"onCreate");
new Thread(new TcpServer()).start();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
mIsServiceDestoryed = true;
super.onDestroy();
}
private class TcpServer implements Runnable{
@Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8688);
} catch (IOException e) {
Log.e(TAG,"servel failed,port:8688");
e.printStackTrace();
return;
}
while (!mIsServiceDestoryed){
try {
final Socket client = serverSocket.accept();
Log.e(TAG,"accept");
new Thread(){
@Override
public void run() {
try {
responseClient(client);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void responseClient(Socket client) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
//这个true很重要啊
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())),true);
out.println("欢迎来到聊天室");
while (!mIsServiceDestoryed){
String str = in.readLine();
Log.e(TAG,"msg from client:"+str);
if (str == null){
break;
}
int i = new Random().nextInt(mDefinedMsg.length);
String msg = mDefinedMsg[i];
out.println(msg);
Log.e(TAG,"send:"+msg);
}
Log.e(TAG,"client quit.");
out.close();
in.close();
client.close();
}
}
第21到26行,定义String数组,用来返回数据给客户端。
第35行,启动一个子线程用来执行循环接收客户端的请求。
第49-80行,子线程的执行内容。55行通过ServerSocket创建Socket连接。63行获得socket对象。
private class TcpServer implements Runnable{
@Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8688);
} catch (IOException e) {
Log.e(TAG,"servel failed,port:8688");
e.printStackTrace();
return;
}
while (!mIsServiceDestoryed){
try {
final Socket client = serverSocket.accept();
Log.e(TAG,"accept");
new Thread(){
@Override
public void run() {
try {
responseClient(client);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
第82到103行,通过socket对象获得IO流。
通过inputstream获得客户端的输入流,通过outputStream写入服务端发给客户端的输出流(服务端随机发送消息给客户端)。
代码如下:
private void responseClient(Socket client) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
//这个true很重要啊
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())),true);
out.println("欢迎来到聊天室");
while (!mIsServiceDestoryed){
String str = in.readLine();
Log.e(TAG,"msg from client:"+str);
if (str == null){
break;
}
int i = new Random().nextInt(mDefinedMsg.length);
String msg = mDefinedMsg[i];
out.println(msg);
Log.e(TAG,"send:"+msg);
}
Log.e(TAG,"client quit.");
out.close();
in.close();
client.close();
}
三、写个客户端App
package haibo.com.socketclient;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends Activity {
private PrintWriter printWriter;
private final String TAG = "MainActivity";
private TextView content_tv;
private EditText edit_query;
private static boolean isFlag = false;
private String content_msg;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
content_msg = "success connect";
Log.e(TAG,content_msg);
content_tv.setText(content_msg);
break;
case 2:
Log.e(TAG, "receive:"+msg.obj);
content_msg=content_msg+"\n"+msg.obj;
content_tv.setText(content_msg);
break;
case 3:
content_msg ="connect failed,retry...";
Log.e(TAG,content_msg);
content_tv.setText(content_msg);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit_query = (EditText) findViewById(R.id.edit_query);
content_tv = (TextView) findViewById(R.id.content_tv);
new Thread(){
@Override
public void run() {
connectTCPServer();
}
}.start();
}
public void send(View view){
String msg =edit_query.getText().toString().trim();
if (!TextUtils.isEmpty(msg)&&printWriter!=null){
printWriter.println(msg);
content_msg=content_msg+"\n"+"client:"+msg;
content_tv.setText(content_msg);
Log.e(TAG, "client:"+msg);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
isFlag = true;
}
private void connectTCPServer() {
Socket socket = null;
while (socket == null){
try {
socket = new Socket("localhost",8688);
printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
handler.sendEmptyMessage(1);
} catch (IOException e) {
SystemClock.sleep(1000);
e.printStackTrace();
handler.sendEmptyMessage(3);
}
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (!MainActivity.isFlag){
//每一秒钟从服务端读取一次数据
SystemClock.sleep(1000);
String msg = br.readLine();
if (msg!=null){
String time = null;
SimpleDateFormat sdf= new SimpleDateFormat("HH:mm:ss");
time = sdf.format(new Date(System.currentTimeMillis()));
final String showedMsg = "server" +time +":"+msg+"\n";
handler.obtainMessage(2,showedMsg).sendToTarget();
}
}
Log.e(TAG, "client:"+"quit...");
printWriter.close();
br.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
第65-70行,和服务器建立socket连接。
new Thread(){
@Override
public void run() {
connectTCPServer();
}
}.start();
其中第4行,connectTCPServer()方法如下:
private void connectTCPServer() {
Socket socket = null;
while (socket == null){
try {
socket = new Socket("localhost",8688);
printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
handler.sendEmptyMessage(1);
} catch (IOException e) {
SystemClock.sleep(1000);
e.printStackTrace();
handler.sendEmptyMessage(3);
}
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (!MainActivity.isFlag){
//每一秒钟从服务端读取一次数据
SystemClock.sleep(1000);
String msg = br.readLine();
if (msg!=null){
String time = null;
SimpleDateFormat sdf= new SimpleDateFormat("HH:mm:ss");
time = sdf.format(new Date(System.currentTimeMillis()));
final String showedMsg = "server" +time +":"+msg+"\n";
handler.obtainMessage(2,showedMsg).sendToTarget();
}
}
Log.e(TAG, "client:"+"quit...");
printWriter.close();
br.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
第5行,主UI线程中直接建立连接会抛异常,所以需要在子线程中建立网络连接。
socket = new Socket("localhost",8688);
第6行,获得输出流,用来给服务端发送消息,写数据。
printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
第7行,建立连接。发送消息给handler,ui显示。
handler.sendEmptyMessage(1);
第15行,获得服务端发来的消息,获得输入流,死循环,从服务器端获取数据。每一秒钟读一次。
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
客户端UI展示如下:
本文,完。