进程间通信除了Bundle,文件共享,Messenger,ContentProvider,ADIL就是Socket了。这里同样简单记录一下。
Socket也被叫做套接字
,是网络通信中的概念,分为TCP和UDP。
Socket通信需要声明权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
不能在主线程访问网络,因为这会导致程序抛出异常android.os.NetworkOnMainThreadException。网络操作也可能会比较耗时,如果放在主线程,就会影响程序的效率,从这个角度来说,也不应该放在主线程。
服务端
/**
* Created by Kevin on 2019/4/10<br/>
* Blog:https://blog.csdn.net/student9128<br/>
* Describe:<br/>
*/
public class TCPServerService extends Service {
private static final String TAG = "TCPServerService";
private boolean mIsServiceDestroyed = false;
private String[] mDefinedMessage = new String[]{"Hello!",
"What is your name,please?",
"It is Sunny,Wonderful!",
"Do your know,i can chat with more than one person",
"I am AI"};
@Override
public void onCreate() {
super.onCreate();
new Thread(new TCPServer()).start();
}
@Override
public void onDestroy() {
super.onDestroy();
mIsServiceDestroyed = true;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private class TCPServer implements Runnable {
@Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8688);
} catch (IOException e) {
Log.d(TAG, "establish tcp server failed,port:8688");
e.printStackTrace();
return;
}
while (!mIsServiceDestroyed) {
try {
final Socket client = serverSocket.accept();
Log.d(TAG, "accept");
new Thread(
) {
@Override
public void run() {
super.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()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())),true);
out.println("Welcome to Chatting Room!!!");
while (!mIsServiceDestroyed) {
String str = in.readLine();
Log.d(TAG, "msg from client:" + str);
if (str == null) {
//客户端断开连接
break;
}
int i = new Random().nextInt(mDefinedMessage.length);
String msg = mDefinedMessage[i];
out.println(msg);
Log.d(TAG, "send:" + msg);
}
in.close();
out.close();
client.close();
}
}
}
客户端
Socket既可以实现进程间通信,也可实现设备间通信。这里将代码修改了一下,添加了ip输入框。通过两个设备来进行通信。
/**
* Created by Kevin on 2019/4/10<br/>
* Blog:https://blog.csdn.net/student9128<br/>
* Describe:<br/>
*/
public class TCPClientActivity extends AppCompatActivity implements View.OnClickListener {
private static final int MESSAGE_RECEIVE_NEW_MSG = 101;
private static final int MESSAGE_SOCKET_CONNECTED = 102;
private Button mSendButton, mOKButton;
private TextView mMessageTextView;
private EditText mMessageEditText;
private EditText mIPEditText;
private PrintWriter mPrintWriter;
private Socket mClientSocket;
private String TAG = getClass().getSimpleName();
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MESSAGE_RECEIVE_NEW_MSG:
mMessageTextView.setText(mMessageTextView.getText() + (String) msg.obj);
break;
case MESSAGE_SOCKET_CONNECTED:
mSendButton.setEnabled(true);
break;
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tcp_client);
mMessageTextView = findViewById(R.id.msg_text);
mMessageEditText = findViewById(R.id.msg_edit);
mSendButton = findViewById(R.id.btn_send);
mSendButton.setOnClickListener(this);
mIPEditText = findViewById(R.id.et_ip);
mOKButton = findViewById(R.id.btn_ok);
mOKButton.setOnClickListener(this);
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.kevin.serverclient", "com.kevin.serverclient.TCPServerService"));
intent.setAction("com.kevin.server.tcp");
if (Build.VERSION.SDK_INT >= 26) {//8.0以后修改了启动方式
startForegroundService(intent);
} else {
startService(intent);
}
}
@Override
protected void onDestroy() {//Activity退出的时候,关闭Client的Socket
if (mClientSocket != null) {
try {
mClientSocket.shutdownInput();
mClientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
super.onDestroy();
}
@Override
public void onClick(View v) {
if (v == mSendButton) {
final String msg = mMessageEditText.getText().toString();
if (!TextUtils.isEmpty(msg) && mPrintWriter != null) {
new Thread() {
@Override
public void run() {
super.run();
mPrintWriter.println(msg);
}
}.start();
mMessageEditText.setText("");
String time = formatDateTime(System.currentTimeMillis());
String shownMsg = "self " + time + ":" + msg + "\n";
mMessageTextView.setText(mMessageTextView.getText() + shownMsg);
}
}
if (v == mOKButton) {
final String trim = mIPEditText.getText().toString().trim();
if (!TextUtils.isEmpty(trim)) {
new Thread() {
@Override
public void run() {
super.run();
connectTCPServer(trim);
}
}.start();
}
}
}
private String formatDateTime(long time) {
return new SimpleDateFormat("(HH:mm:ss)").format(new Date(time));
}
private void connectTCPServer(String ip) {
Socket socket = null;
while (socket == null) {
try {
socket = new Socket(ip, 8688);
mClientSocket = socket;
mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
Log.d(TAG, "connect server successfully");
} catch (IOException e) {
e.printStackTrace();
SystemClock.sleep(1000);
Log.d(TAG, "connect tcp server failed, retrying...");
}
}
try {//服务连接成功,代码中不断去获取服务端的消息
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (!TCPClientActivity.this.isFinishing()) {
String msg = br.readLine();
Log.d(TAG, "receive: " + msg);
if (msg != null) {
String time = formatDateTime(System.currentTimeMillis());
String shownMsg = "server " + time + ":" + msg + "\n";
mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG, shownMsg).sendToTarget();
}
}
mPrintWriter.close();
br.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}