Socket 也称为 “嵌套字”,是计算机网络中的概念,分为流式嵌套字(TCP)和用户数据报嵌套字(UDP)。
不同用户进程通过 Socket 进行通信也是一种 IPC 方式。
在使用 Socket 通信前应在 AndroidManifest 中声明权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
1、服务端
我们需要一个 Service 作为服务端,声明如下:
<service android:name=".socket.SocketService" android:enabled="true" android:exported="true" android:process=":remote" />
|
Socket 服务端在 Service 启动时,会建立 TCP 连接并监听 8688 端口。
public class SocketService extends Service {
private static final String TAG = "SocketService";
private boolean isDestroyed = false; private String[] messages = new String[]{ "你好啊,哈哈", "请问你叫什么名字呀?", "今天北京天气不错啊", "你知道吗?我可是可以和多个人同时聊天的哦", "给你讲个笑话吧:据说爱笑的人运气不会太差,不知道真假。" };
public SocketService() { }
@Override public void onCreate() { super.onCreate(); new Thread(new TCPServer()).start(); }
@Override public IBinder onBind(Intent intent) { return null; }
@Override public void onDestroy() { isDestroyed = true; super.onDestroy(); } private class TCPServer implements Runnable { @Override public void run() { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(8688); } catch (IOException e) { e.printStackTrace(); } while (!isDestroyed) { try { final Socket client = serverSocket.accept(); Log.d(TAG, "accept"); new Thread() { @Override public void run() { responseClient(client); } }.start();
} catch (IOException e) { e.printStackTrace(); } } }
private void responseClient(Socket client) { try { BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true); Log.d(TAG, "欢迎来到聊天室!"); out.println("欢迎来到聊天室!"); while (!isDestroyed) { String line = in.readLine(); Log.d(TAG, "message from Client: " + line); if (line == null) break; int i = new Random().nextInt(messages.length); String message = messages[i]; out.println(message); Log.d(TAG, "response to Client: " + message); } out.close(); in.close();
client.close(); } catch (IOException e) { e.printStackTrace(); } } } }
|
当与客户端建立连接后,新建 Socket 客户端,接收消息并作出响应。
2、客户端
客户端部分首先启动 Socket 服务,并且在连接失败后会不断重新尝试连接。
public class SocketActivity extends AppCompatActivity { private static final String TAG = "SocketActivity";
private Button bt_send; private EditText et_receive; private TextView tv_message;
private PrintWriter mPrintWriter;
private Socket mClientSocket;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_socket);
initView();
Intent service = new Intent(this, SocketService.class); startService(service); new Thread() { @Override public void run() { connectSocketServer(); } }.start(); }
private void initView() { et_receive = findViewById(R.id.et_receive); bt_send = findViewById(R.id.bt_send); tv_message = findViewById(R.id.tv_message); bt_send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final String msg = et_receive.getText().toString(); if (!TextUtils.isEmpty(msg) && mPrintWriter != null) { Log.d(TAG, "onClick: " + msg); new Thread(new Runnable() { @Override public void run() { mPrintWriter.println(msg); } }).start(); tv_message.setText(tv_message.getText() + "\n" + "客户端:" + msg); et_receive.setText(""); } } }); }
private void connectSocketServer() { Socket socket = null; while (socket == null) { try { socket = new Socket("localhost", 8688); mClientSocket = socket; mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); } catch (IOException e) { SystemClock.sleep(1000); } } try { BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); while (!isFinishing()) { final String msg = br.readLine(); if (msg != null) { runOnUiThread( new Runnable() { @Override public void run() { tv_message.setText(tv_message.getText() + "\n" + "服务端:" + msg); } } ); } } mPrintWriter.close(); br.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } }
@Override protected void onDestroy() { if (mClientSocket != null) { try { mClientSocket.shutdownInput(); mClientSocket.close(); } catch (IOException e) { e.printStackTrace(); } } super.onDestroy(); } }
|
主要使用 socket.getOutputStream() 和 socket.getInputStream() 方法分别发送、接收服务端消息。
打印日志如下:

最终效果如下:

到这里把 Android IPC 通信的几种实现方式基本看了一遍,但是在 Binder 机制原理方面还有欠缺,后面再深入学习。
参考资料
1、《Android开发艺术探索》 – 2.4.6 使用 Socket
2、Android IPC机制(五)用Socket实现跨进程聊天程序 | 刘望舒的博客
http://liuwangshu.cn/application/ipc/5-socket.html