IPC跨进程交互(3)Socket的使用
来源:互联网 发布:域名价格查询 编辑:程序博客网 时间:2024/06/04 18:19
前两篇说了两种交互了,这次来说socket,socket其实在通信交互上面很常用,虽然我目前没用到过实现项目。不过也是一种常用的跨进程交互,这边就来讲解下做一个聊天室!本篇也是参考了任玉刚老师的Android艺术
开始,还是从看效果开始。
Service
Client
下面开始讲解代码。
1.Service
先创建一个SocketService的服务,代码如下
SocketService.java
package com.gjn.myservice;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.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.io.Reader;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;import java.util.List;import java.util.Random;import java.util.concurrent.atomic.AtomicBoolean;public class SocketService extends Service { private static final String TAG = "SocketService"; private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false); private List<String> mDefinedMsg; @Override public void onCreate() { mDefinedMsg = new ArrayList<>(); for (int i = 0; i < 10; i++) { mDefinedMsg.add("msg_"+i); } new Thread(new TcpServer()).start(); super.onCreate(); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { mIsServiceDestoryed.set(true); super.onDestroy(); } private class TcpServer implements Runnable { @Override public void run() { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(8888); } catch (IOException e) { Log.e(TAG, "端口:8888 出错"); e.printStackTrace(); return; } while (!mIsServiceDestoryed.get()) { try { final Socket client = serverSocket.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 { //接受消息 InputStream is = client.getInputStream(); Reader reader = new InputStreamReader(is); BufferedReader in = new BufferedReader(reader); //发送消息 OutputStream os = client.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(os); BufferedWriter bw = new BufferedWriter(osw); PrintWriter out = new PrintWriter(bw, true); //循环交互中 while (!mIsServiceDestoryed.get()) { //获取的消息 String str = in.readLine(); Log.e(TAG, "client: "+str); if (str == null){ //离开socket break; } if (str.equals("我要离开socket")) { //离开socket break; } //发送的消息 int i = new Random().nextInt(mDefinedMsg.size()); String msg = mDefinedMsg.get(i); out.println(msg); Log.e(TAG, "service: "+msg); } //离开 Log.e(TAG, "responseClient: 退出socket"); //关闭流 in.close(); out.close(); client.close(); }}
开始的onCreate创建线程和onDestroy停止交互这边就不讲解了。
只来看下如何交互的吧!
ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(8888); } catch (IOException e) { Log.e(TAG, "端口:8888 出错"); e.printStackTrace(); return; }创建一个ServerSocket 对象 占用8888端口
之后再开启一个新线程循环获取端口传来的BufferReader
发送消息用的是PrintWriter发送
最后交互结束后关闭使用的流
然后说下跨进程交互需要设置xml文件
Service的AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.gjn.myservice"> <permission android:name="com.gjn.permission.A" android:protectionLevel="normal" /> <uses-permission android:name="com.gjn.permission.A" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".MessengerService" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.gjn.myservice.Messenger_Service" /> </intent-filter> </service> <service android:name=".AIDLService" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.gjn.myservice.AIDLService" /> </intent-filter> </service> <service android:name=".SocketService" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.gjn.myservice.SocketService" /> </intent-filter> </service> </application></manifest>设置了Action
2.Client
在来看下Client的代码吧!
首先要说下。因为用到端口,所以AndroidManifest.xml文件中必须加入权限
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>下面是完整的AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.gjn.myclient"> <uses-permission android:name="com.gjn.permission.A" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name="com.gjn.myclient.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.gjn.myclient.MessengerActivity" /> <activity android:name="com.gjn.myclient.AIDLActivity" /> <activity android:name="com.gjn.myclient.SocketActivity" /> <activity android:name="com.gjn.myclient.BundleActivity" /> </application></manifest>
然后来创建一个SocketActivity,代码如下
布局设置
代码
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.gjn.myclient.SocketActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="连接服务器" android:id="@+id/btn_link" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tv_socket" android:layout_alignParentTop="true" android:layout_alignParentStart="true" android:layout_alignParentEnd="true" android:layout_above="@+id/btn_link" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="发送消息" android:id="@+id/btn_send" android:layout_below="@+id/btn_link" android:layout_alignEnd="@+id/tv_socket" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="离开聊天室" android:id="@+id/btn_quit" android:layout_below="@+id/btn_send" android:layout_centerHorizontal="true" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/et_msg" android:layout_above="@+id/btn_quit" android:layout_alignParentStart="true" android:layout_toStartOf="@+id/btn_send" android:hint="输入聊天内容" /></RelativeLayout>
SocketActivity.java
package com.gjn.myclient;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.util.Log;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.io.Reader;import java.net.Socket;public class SocketActivity extends AppCompatActivity { private static final String TAG = "SocketActivity"; private TextView tv_socket; private EditText et_msg; private Button btn_link; private Button btn_send; private Button btn_quit; private Socket mClientSocket; private PrintWriter mPrintWriter; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: tv_socket.setText(tv_socket.getText() + (String) msg.obj); break; case 2: tv_socket.setText("欢迎来到聊天室"); Toast.makeText(SocketActivity.this, "link susuccess", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_socket); findview(); onclick(); Intent intent = new Intent(); intent.setAction("com.gjn.myservice.SocketService"); intent.setPackage("com.gjn.myservice"); startService(intent); } private void findview() { tv_socket = (TextView) findViewById(R.id.tv_socket); et_msg = (EditText) findViewById(R.id.et_msg); btn_link = (Button) findViewById(R.id.btn_link); btn_send = (Button) findViewById(R.id.btn_send); btn_quit = (Button) findViewById(R.id.btn_quit); } private void onclick() { btn_link.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { connectService(); } }).start(); } }); btn_send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final String send = et_msg.getText().toString(); if (!TextUtils.isEmpty(send) && mPrintWriter != null) { mPrintWriter.println(send); et_msg.setText(""); tv_socket.setText(tv_socket.getText() + "\nself: " + send); } } }); btn_quit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mPrintWriter != null) { close(); tv_socket.setText(""); Log.e(TAG, "link disconnect"); Toast.makeText(SocketActivity.this, "link disconnect", Toast.LENGTH_SHORT).show(); } } }); } private void close() { mPrintWriter.println("我要离开socket"); mPrintWriter.close(); mPrintWriter = null; try { mClientSocket.shutdownInput(); mClientSocket.close(); } catch (IOException e) { e.printStackTrace(); } mClientSocket = null; } private Socket link() { while (mClientSocket == null) { try { mClientSocket = new Socket("localhost", 8888); OutputStream os = mClientSocket.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(os); BufferedWriter bw = new BufferedWriter(osw); mPrintWriter = new PrintWriter(bw, true); mHandler.sendEmptyMessage(2); Log.e(TAG, "link susuccess"); return mClientSocket; } catch (IOException e) { SystemClock.sleep(1000); e.printStackTrace(); } } return null; } private void connectService() { link(); try { //获取服务器的返回消息 InputStream is = mClientSocket.getInputStream(); Reader reader = new InputStreamReader(is); BufferedReader in = new BufferedReader(reader); while (!SocketActivity.this.isFinishing()) { String msg = in.readLine(); if (msg != null) { mHandler.obtainMessage(1, "\nservice: " + msg).sendToTarget(); } } if (mPrintWriter != null){ mPrintWriter.close(); } in.close(); if (mClientSocket != null){ mClientSocket.close(); } } catch (IOException e) { e.printStackTrace(); } } @Override protected void onDestroy() { if (mClientSocket != null) { try { mClientSocket.shutdownInput(); mClientSocket.close(); Log.e(TAG, "onDestroy: mClientSocket disconnect"); } catch (IOException e) { e.printStackTrace(); } } super.onDestroy(); }}
下面也来讲解下代码
首先是连接
private Socket link() { while (mClientSocket == null) { try { mClientSocket = new Socket("localhost", 8888); OutputStream os = mClientSocket.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(os); BufferedWriter bw = new BufferedWriter(osw); mPrintWriter = new PrintWriter(bw, true); mHandler.sendEmptyMessage(2); Log.e(TAG, "link susuccess"); return mClientSocket; } catch (IOException e) { SystemClock.sleep(1000); e.printStackTrace(); } } return null; }每1s一次的重新创建Socket,当然是如果没有创建成功的话!
这边也来说下交互,发现在Client中获取消息也变成了BufferReader,发送消息也是PrintWriter
try { //获取服务器的返回消息 InputStream is = mClientSocket.getInputStream(); Reader reader = new InputStreamReader(is); BufferedReader in = new BufferedReader(reader); while (!SocketActivity.this.isFinishing()) { String msg = in.readLine(); if (msg != null) { mHandler.obtainMessage(1, "\nservice: " + msg).sendToTarget(); } } if (mPrintWriter != null){ mPrintWriter.close(); } in.close(); if (mClientSocket != null){ mClientSocket.close(); } } catch (IOException e) { e.printStackTrace(); }
btn_send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final String send = et_msg.getText().toString(); if (!TextUtils.isEmpty(send) && mPrintWriter != null) { mPrintWriter.println(send); et_msg.setText(""); tv_socket.setText(tv_socket.getText() + "\nself: " + send); } } });
说明了,交互的时候接收方都是用BufferReader接收消息,用PrintWriter发送消息
这边因为不是在主线程,所以修改UI的东西需要转回到UI线程,所以使用了mHandler来实现修改UI
在看下断开连接
btn_quit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mPrintWriter != null) { close(); tv_socket.setText(""); Log.e(TAG, "link disconnect"); Toast.makeText(SocketActivity.this, "link disconnect", Toast.LENGTH_SHORT).show(); } } });
private void close() { mPrintWriter.println("我要离开socket"); mPrintWriter.close(); mPrintWriter = null; try { mClientSocket.shutdownInput(); mClientSocket.close(); } catch (IOException e) { e.printStackTrace(); } mClientSocket = null; }这边是发送了一个消息“我要离开socket”,这是因为上面的Service有做判断,可以翻上去看下。这个是跳出交互循环的一个条件
其他就是初始化了一下Socket和PrintWriter。
至此Socket也算讲解完了。
上面其实只要Service中的循环反馈消息中,加个UI发送消息就可以实现Service自己返回消息而不是自动随即生成返回消息
//循环交互中 while (!mIsServiceDestoryed.get()) { //获取的消息 String str = in.readLine(); Log.e(TAG, "client: "+str); if (str == null){ //离开socket break; } if (str.equals("我要离开socket")) { //离开socket break; } //发送的消息 int i = new Random().nextInt(mDefinedMsg.size()); String msg = mDefinedMsg.get(i); out.println(msg); Log.e(TAG, "service: "+msg); }这边的发送消息下面就是循环反馈。只需要改成自己输入反馈就好了!
- IPC跨进程交互(3)Socket的使用
- IPC跨进程交互(1)Messenger的使用
- IPC跨进程交互(2)AIDL的使用
- IPC跨进程交互(4)Binder池的使用
- 跨进程的通信 [IPC]
- 跨进程的通信 [IPC]
- IPC(跨进程)基础知识
- 使用Socket处理跨进程的实时聊天
- Service跨进程的绑定和交互
- android跨进程通信(IPC):使用AIDL
- android跨进程通信(IPC):使用AIDL
- android跨进程通信(IPC):使用AIDL
- android跨进程通信(IPC):使用AIDL
- android跨进程通信(IPC):使用AIDL
- android跨进程通信(IPC):使用AIDL
- android跨进程通信(IPC):使用AIDL
- android跨进程通信(IPC):使用AIDL
- android跨进程通信(IPC):使用AIDL
- 成员变量和局部变量的区别
- Linux中变量#,#,@,0,0,1,2,2,*,$$,$?的含义
- git的入门
- 模拟数学:除法
- 1分钟教你破解风行电视禁止安装应用!
- IPC跨进程交互(3)Socket的使用
- img.shape img.size
- matlab学习一
- php gettext方式实现UTF-8国际化多语言(i18n)
- BZOJ 1877 最小费用流
- 请教:linux下的/opt目录是做什么用的?
- 学习笔记,持续更新中
- php 通过include方式实现国际化多语言(i18n)
- jquery点赞和取消点赞插件