Android IPC机制(五)用Socket实现跨进程聊天程序

1.Socket简介

Socket也称作“套接字“,是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信。它分为流式套接字和数据包套接字,分别对应网络传输控制层的TCP和UDP协议。TCP协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。它使用三次握手协议建立连接,并且提供了超时重传机制,具有很高的稳定性。UDP协议则是是一种无连接的协议,且不对传送数据包进行可靠性保证,适合于一次传输少量数据,UDP传输的可靠性由应用层负责。在网络质量令人十分不满意的环境下,UDP协议数据包丢失会比较严重。但是由于UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多。 
这里写图片描述

从上图我们也可以看出,不同的用户进程通过Socket来进行通信,所以Socket也是一种IPC方式,接下来我们用TCP服务来实现一个简单的聊天程序。

2.实现聊天程序服务端

配置

首先我们来实现服务端,当然要使用Socket我们需要在AndroidManifest.xml声明如下的权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

我们需要实现一个远程的Service来当作聊天程序的服务端,AndroidManifest.xml文件中配置service:

<serviceandroid:name=".SocketServerService"android:process=":remote" />

实现Service

接下来我们在Service启动时,在线程中建立TCP服务,我们监听的是8688端口,等待客户端连接,当客户端连接时就会生成Socket。通过每次创建的Socket就可以和不同的客户端通信了。当客户端断开连接时,服务端也会关闭Socket并结束结束通话线程。服务端首先会向客户端发送一条消息:“您好,我是服务端”,并接收客户端发来的消息,将收到的消息进行加工再返回给客户端。

package com.example.liuwangshu.moonsocket;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.text.TextUtils;
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;public class SocketServerService extends Service {private boolean isServiceDestroyed = false;@Overridepublic void onCreate() {new Thread(new TcpServer()).start();super.onCreate();}@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.throw new UnsupportedOperationException("Not yet implemented");}private class TcpServer implements Runnable {@Overridepublic void run() {ServerSocket serverSocket;try {//监听8688端口serverSocket = new ServerSocket(8688);} catch (IOException e) {return;}while (!isServiceDestroyed) {try {// 接受客户端请求,并且阻塞直到接收到消息final Socket client = serverSocket.accept();new Thread() {@Overridepublic 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.println("您好,我是服务端");while (!isServiceDestroyed) {String str = in.readLine();Log.i("moon", "收到客户端发来的信息"   str);if (TextUtils.isEmpty(str)) {//客户端断开了连接Log.i("moon", "客户端断开连接");break;}String message = "收到了客户端的信息为:"   str;// 从客户端收到的消息加工再发送给客户端out.println(message);}out.close();in.close();client.close();}@Overridepublic void onDestroy() {isServiceDestroyed = true;super.onDestroy();}
}

3.实现聊天程序客户端

客户端Activity会在onCreate方法中启动服务端,并开启线程连接服务端Socket。为了确保能连接成功,采用了超时重连的策略,每次连接失败时都会重新建立连接。连接成功后,客户端会收到服务端发送的消息:“您好,我是服务端”,我们也可以在EditText输入字符并发送到服务端。

package com.example.liuwangshu.moonsocket;import android.content.Intent;
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.Button;
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;public class SocketClientActivity extends AppCompatActivity {private Button bt_send;private EditText et_receive;private Socket mClientSocket;private PrintWriter mPrintWriter;private TextView tv_message;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_socket);initView();Intent service = new Intent(this, SocketServerService.class);startService(service);new Thread() {@Overridepublic void run() {connectSocketServer();}}.start();}private void initView() {et_receive= (EditText) findViewById(R.id.et_receive);bt_send= (Button) findViewById(R.id.bt_send);tv_message= (TextView) this.findViewById(R.id.tv_message);bt_send.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {final String msg = et_receive.getText().toString();//向服务器发送信息if(!TextUtils.isEmpty(msg)&&null!=mPrintWriter) {mPrintWriter.println(msg);tv_message.setText(tv_message.getText()   "\n"   "客户端:"   msg);et_receive.setText("");}}});}private void connectSocketServer() {Socket socket = null;while (socket == null) {try {//选择和服务器相同的端口8688socket = 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() {@Overridepublic void run() {tv_message.setText(tv_message.getText()   "\n"   "服务端:"   msg);}});}}mPrintWriter.close();br.close();socket.close();} catch (IOException e) {e.printStackTrace();}}}

布局很简单(activity_socket.xml):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@ id/tv_message"android:layout_width="match_parent"android:layout_height="400dp" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="50dp"android:layout_alignParentBottom="true"android:orientation="horizontal"><EditTextandroid:id="@ id/et_receive"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="2"/><Buttonandroid:id="@ id/bt_send"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="向服务器发消息" /></LinearLayout>
</RelativeLayout>

4.运行聊天程序

运行程序,我们可以看到客户端和服务端是两个进程: 
这里写图片描述

客户端首先会收到服务端的信息:”您好,我是服务端”,接下来我们向服务端发送“我想要怒放的生命”。这时候服务端收到了这条信息并返回给客户端加工后的这条信息: 
这里写图片描述

  

  

https://github.com/henrymorgen/MoonSocket  

  

本文转载于:猿2048⇨https://www.mk2048.com/blog/blog.php?id=bbjckkj&title=Android IPC机制(五)用Socket实现跨进程聊天程序

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/370512.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ArcGIS 网络分析[4] 网络数据集深入浅出之连通性、网络数据集的属性及转弯要素...

前面介绍完了如何创建网络数据集、如何使用网络分析功能&#xff0c;当然还有的读者会迷惑于一些更深层次的问题&#xff0c;比如网络数据集的连通性问题等。 因为不可能面面俱到&#xff0c;我只能挑重点来阐述&#xff0c;我觉得网络数据集的连通性、属性和转弯是初学者中比较…

java获取byte 长度_java获取字节的长度.

我们经常要获取中文,数字,或者英文字符所占字节的长度,下面就列出各种编码格式下所占字节的长度:代码如下:package pack.java.midea.dao;import java.io.UnsupportedEncodingException;/*** 测试;* author zhouhaitao* 2012-5-17*/public class Test {/*** param args* throws …

Batoo JPA –比领先的JPA提供商快15倍

介绍 我早在2000年代就喜欢JPA 1.0。 我甚至在稳定版本发布之前就将其与EJB 3.0一起使用。 我非常喜欢它&#xff0c;因此我为JBoss 3.x实现贡献了一些零碎的部分。 那时我们公司规模还很小。 创建新功能和应用程序比性能更重要&#xff0c;因为我们有很多想法&#xff0c;我…

python软件是哪个国家的品牌_有哪些好用的软件被国人误认为是外国研发的?

国产软件被标榜上了英文&#xff0c;即便不是英文&#xff0c;用拼音写出来&#xff0c;也会有人误认为是国外的软件。因为这样可以显得高大上&#xff0c;为什么我们会有这样的想法&#xff0c;是崇洋媚外吗&#xff0c;并不是&#xff0c;而是之前的国产软件的确有不少让我们…

简单的Session案例 —— 一次性验证码

一次性验证码的主要目的就是为了限制人们利用工具软件来暴力猜测密码&#xff0c;其原理与利用Session防止表单重复提交的原理基本一样&#xff0c;只是将表单标识号变成了验证码的形式&#xff0c;并且要求用户将提示的验证码手工填写进一个表单字段中&#xff0c;而不是通过表…

[BZOJ2064]分裂

[BZOJ2064]分裂 试题描述 背景&#xff1a; 和久必分&#xff0c;分久必和。。。 题目描述&#xff1a; 中国历史上上分分和和次数非常多。。通读中国历史的WJMZBMR表示毫无压力。 同时经常搞OI的他把这个变成了一个数学模型。 假设中国的国土总和是不变的。 每个国家都可以用他…

CSS3选择器

基本选择器 回顾选择器 通配符选择器元素选择器类选择器ID选择器后代选择器新增基本选择器 子元素选择器相邻兄弟选择器通用兄弟选择器群组选择器 子元素选择器 概念&#xff1a;子元素选择器只能选择某元素的子元素 语法&#xff1a;父元素 > 子元素 &#xff08;Fathe…

eclipse java工程目录_转载:Eclipse下的java工程目录

对新手来讲&#xff0c;一个Java工程内部的多个文件夹经常会让大家困惑。更可恶的是莫名其妙的路径问题&#xff0c;在Eclipse编写Java程序中&#xff0c;出现频率最高的错误很可能就是路径问题。这些问题原因其实都是一个&#xff0c;就是关于Java工程内的文件结构理解不清&am…

作为JBoss AS 7模块运行Drools 5.4.0 Final

Drools 5引入了业务逻辑集成平台&#xff0c;该平台为规则&#xff0c;工作流和事件处理提供了统一的集成平台。 它是从头开始设计的&#xff0c;因此每个方面都是一流的公民&#xff0c;毫不妥协。 Drools 5已分为4个主要子项目&#xff1a; Drools Guvnor&#xff08;BRMS …

postgres 支持的线程数_线程池被打满了怎么处理呢,你是否真的了解线程池?

0、前言线程池&#xff0c;顾名思义就是线程的池子&#xff0c;在每次需要取线程去执行任务的时候&#xff0c;没必要每次都创建新线程执行&#xff0c;线程池就是起着维护线程的作用&#xff0c;当有任务的时候就取出一个线程执行&#xff0c;如果任务执行完成则把线程放回到池…

[树形DP]没有上司的舞会

题目链接 思考 首先本题中的关系是一种树形结构&#xff0c;而且符号最优子结构和无后效性&#xff0c;所以可以进行记忆化搜索。 那么首先要在这颗树中选出一个点作为根节点&#xff0c;按照习惯我们将没有父节点的点作为根节点。 接下来要思考的是 状态&#xff1a; dp[i][0…

网页自适应

1.viewport标签 基本语法&#xff1a; <meta name”viewport” content”widthdevice-width,initial-scale1” /> 上面这行代码的意思是&#xff0c;面积的100%&#xff0c;网页宽度默认等于屏幕宽度&#xff08;widthdevice-width&#xff09;, 原始缩放比例&#x…

java 大数处理

头文件&#xff1a;import java.util.*;import java.math.*; Scanner cin Scanner (System.in);//读入while(cin.hasNext())//等价于!EOFncin.nextInt();//读入一个int型的数ncin.nextBigInteger();//读入一个大整数 输出&#xff1a; System.out.print(n);//打印nSystem.out.…

java provider_Java SPI(Service Provider Interface)

//ServiceLoader实现了Iterable接口&#xff0c;可以遍历所有的服务实现者public final class ServiceLoaderimplements Iterable{//查找配置文件的目录private static final String PREFIX "META-INF/services/";//表示要被加载的服务的类或接口private final Clas…

带有自定义注释的Java注释教程

Java注释提供有关代码的信息&#xff0c;并且它们对所注释的代码没有直接影响。 在本教程中&#xff0c;我们将学习Java注释&#xff0c;如何编写自定义注释 &#xff0c;注释用法以及如何使用反射来解析注释 。 注释是在Java 1.5中引入的&#xff0c;现在它已在Hibernate&…

mybatis通用mapper_全网最全Mapper解析,附实操代码帮你更好理解

今天给大家介绍一位老朋友当你第一次接触Java开发的时候&#xff0c;这个老朋友就和你形影不离&#xff0c;当你要进行ORM的时候&#xff0c;单表的增删改查&#xff0c;这位老朋友给了你极大的帮助&#xff0c;不知道你想到他了吗&#xff1f;对&#xff0c;这就是通用mapper&…

初尝微信小程序2-基本框架

基本框架&#xff1a; .wxml &#xff1a;页面骨架 .wxss &#xff1a;页面样式 .js &#xff1a;页面逻辑 描述一些行为 .json &#xff1a;页面配置 创建一个小程序之后&#xff0c;app.js,app.json,app.wxss是必须的&#xff0c;而且名字也不能随意更改&#xff0c;…

JSP内置对象,动作,指令总结

总的来说关于JSP界面有九大内置对象,7大动作,三大指令,现在博主就将这些粘贴出来,此文是很久前整理的学习笔记,如有雷同请谅解! jsp九大内置对象:1>out 向客户端输出数据,字节流.如out.print(" dgaweyr"); 2>request 接收客户端的http请求.String getParameter…

洛谷 P1795 无穷的序列_NOI导刊2010提高(05)

P1795 无穷的序列_NOI导刊2010提高&#xff08;05&#xff09; 题目描述 有一个无穷序列如下&#xff1a; 110100100010000100000… 请你找出这个无穷序列中指定位置上的数字 输入输出格式 输入格式&#xff1a;第一行一个正整数N&#xff0c;表示询问次数&#xff1b; 接下来的…

java 取字符串中的数字_java截取字符串中的数字

随便给你一个含有数字的字符串&#xff0c;比如&#xff1a;String s"eert343dfg56756dtry66fggg89dfgf";那我们如何把其中的数字提取出来呢&#xff1f;大致有以下几种方法&#xff0c;正则表达式&#xff0c;集合类&#xff0c;还有就是String类提供的方法。1 Stri…