socket是通过网络来进行进程间通信的。socket也称为“套接字”,是网络通信中的概念,分为流式套接字和用户数据报套接字两种,分别对应网络传输控制中TCP和UDP协议。TCP协议是面向连接的协议,提供稳定的双向通信功能,TCP连接的建立需要经过“经过三次握手”,还提供了超时重传的机制,具有很高的稳定性。而UDP是无连接的,提供不稳定的单身通信功能,UDP也可以实现双向通信功能。在性能上,UDP具有更好的效率,其缺点是不保证数据能够正确传输,尤其在网络拥塞的情况。
接下来介绍的是一个聊天程序,两个进程可以通过socket来实现信息的传输,socket本身可以传递任意字节流,这里仅传输文本,很显然这是一种IPC方式。
首先要声明权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
建立一个远程TCP服务:
public class TCPServerService extends Service {
private boolean isServiceDestoryed = false;
private String[] mDefinedMessages = new String[]{"你好", "what's you name?", "我很聪明"};
@Override
public void onCreate() {
new Thread(new TcpServer()).start();
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
isServiceDestoryed = true;
super.onDestroy();
}
private class TcpServer implements Runnable {
@Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8688);
} catch (IOException e) {
System.err.println("建立tcp服务失败,port:8688");
e.printStackTrace();
return;
}
/**
* 此处循环接收客户端请求(有客户端连接就可做出反应,可同时和多个客户端连接)
* 每次有客户端连接就会生成一个新的socket
*/
while (!isServiceDestoryed) {
try {
//接收客户端请求
final Socket client = serverSocket.accept();
System.out.println("accepted");
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()));
//用于向客户端发送消息
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(client.getOutputStream())), true);
out.print("welcome!");
while (!isServiceDestoryed) {
String str = in.readLine();
System.out.println("msg from client:" + str);
if (str == null) {
//客户端断开连接
break;
}
int i = new Random().nextInt(mDefinedMessages.length);
String msg = mDefinedMessages[i];
out.print(msg);
System.out.println("send :" + msg);
}
System.out.println("client out");
//关闭流
out.close();
in.close();
client.close();
}
}
接下来是客户端Activity,在onCreate里开户一个线程去连接服务端socket,为了能够确定连接成功,这里采用了超时重连的策略,为了降低重连的开销加入了休眠机制sleep。
package com.example.administrator.myapplication.socket;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.TextView;
import com.example.administrator.myapplication.R;
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;
public class SocketActivity extends AppCompatActivity {
//接收到了消息
private static final int MSG_RECEIVE = 1;
//连接服务端
private static final int MSG_CONNECTED = 2;
private TextView msgTextView;
private AutoCompleteTextView input;
private Button sendBtn;
private PrintWriter printWriter;
private Socket mClientSocket;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_RECEIVE:
msgTextView.setText(msgTextView.getText() + "\n" + String.valueOf(msg.obj));
break;
case MSG_CONNECTED:
sendBtn.setEnabled(true);
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_socket);
msgTextView = (TextView) findViewById(R.id.textView);
input = (AutoCompleteTextView) findViewById(R.id.input);
sendBtn = (Button) findViewById(R.id.button);
Intent service = new Intent(this, TCPServerService.class);
startService(service);
new Thread() {
@Override
public void run() {
connectTCPServer();
}
}.start();
}
private void connectTCPServer() {
Socket socket = null;
while (socket == null) {
try {
socket = new Socket("localhost", 8688);
mClientSocket = socket;
printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
handler.sendEmptyMessage(MSG_CONNECTED);
System.out.println("连接成功!");
} catch (IOException e) {
e.printStackTrace();
SystemClock.sleep(1000);
System.out.println("连接失败!重试中。。。");
}
}
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (!SocketActivity.this.isFinishing()){//当前activity没有关闭
String msg = bufferedReader.readLine();
System.out.println("接收:" + msg);
if (msg != null) {
handler.obtainMessage(MSG_RECEIVE, msg).sendToTarget();
}
}
System.out.println("quit...");
printWriter.close();
bufferedReader.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void onClick(View view) {
int id = view.getId();
switch (id){
case R.id.button:
final String msg = input.getText().toString();
if(!TextUtils.isEmpty(msg) && printWriter != null){
printWriter.println(msg);
input.setText("");
msgTextView.setText(msgTextView.getText() + "\n" + String.valueOf(msg));
}
}
}
@Override
protected void onDestroy() {
if (mClientSocket != null) {
try {
mClientSocket.shutdownInput();
mClientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
super.onDestroy();
}
}
注意:socket不用时记得关闭!!!
这里客户端成功连接服务端后,用while循环来不断去读取服务端发来的消息,只有当activity退出时,退出循环并关闭socket。
参考:android开发艺术探索
网友评论