本文首发于微信公众号「后厂技术官」

1.Socket简介

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

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

2.实现聊天程序服务端

配置

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

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

android: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;

@Override

public void onCreate(){

new Thread(new TcpServer()).start();

super.onCreate();

}

@Override

public IBinder onBind(Intent intent){

// TODO: Return the communication channel to the service.

throw new UnsupportedOperationException("Not yet implemented");

}

private class TcpServer implements Runnable{

@Override

public void run(){

ServerSocket serverSocket;

try {

//监听8688端口

serverSocket = new ServerSocket(8688);

} catch (IOException e) {

return;

}

while (!isServiceDestroyed) {

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{

// 用于接收客户端消息

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();

}

@Override

public 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;

@Override

protected void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_socket);

initView();

Intent service = new Intent(this, SocketServerService.class);

startService(service);

new Thread() {

@Override

public 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() {

@Override

public 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 {

//选择和服务器相同的端口8688

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();

}

}

}

布局很简单(activity_socket.xml):

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/tv_message"

android:layout_width="match_parent"

android:layout_height="400dp" />

android:layout_width="match_parent"

android:layout_height="50dp"

android:layout_alignParentBottom="true"

android:orientation="horizontal">

android:id="@+id/et_receive"

android:layout_width="0dp"

android:layout_height="match_parent"

android:layout_weight="2"

/>

android:id="@+id/bt_send"

android:layout_width="0dp"

android:layout_height="match_parent"

android:layout_weight="1"

android:text="向服务器发消息" />

4.运行聊天程序

运行程序,我们可以看到客户端和服务端是两个进程:

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

android跨进程关闭服务器,Android IPC机制(五)用Socket实现跨进程聊天程序相关推荐

  1. android通讯录上传服务器,Android 实现读取通讯录并上传服务器

    关键技术 - 内容解析者Resolver - ListView - Socket网络编程 权限申请 //需要在Manifest.xml文件中申请权限 布局: xmlns:app="http: ...

  2. 利用Java GUI,结合Java Socket,Java多线程,服务器,制作一个简单的具有界面的多用户实时聊天程序(从GUI,到Socket,到多线程,到服务器,项目级别详细教程)

    目录 规划 Java GUI设计 Java Socket Java 服务器 利用 IntelliJ IDEA软件为例 首先,我们应当了解,像运行在两台电脑或者手机终端这样的程序一般是没有办法直接相互发 ...

  3. Android开发艺术探索--第二章IPC机制(2)之Binder

    最近在拜读任主席的Android开发艺术探索,现在看了一半,再回头看前面的,感觉跟没有看一样,所以还是把知识点总结一下吧,这一节咱们来讲一下IPC中的Binder 直观来说,Binder是Androi ...

  4. android 电源管理 关闭屏幕,Android之PowerManager电源管理

    翻译来源PowerManager 这个类让你拥有控制设备状态的权利. 使用这个api类会很明显地影响设备电量的使用时长.除非你确实需要PowerManager.WakeLock否则不要轻易使用它们,并 ...

  5. android json传输数据到服务器,Android中post请求传递json数据给服务端的实例

    在最近的项目中有个需求是这样的: 入参封装成JSON,EXAMPLE: { "uuid": "iamauuid", "clientType" ...

  6. android ios 上传图片到服务器,Android与iOS手机照片互传技巧分享

    眼下,手握Android与iOS双手机的用户不在少数,比如一个移动或联通版的iPhone合约机再加上一个电信版的Android合约机.那么,当平常使用这两类不同操作系统手机时,各自手机中存储的照片又该 ...

  7. android bitmap上传服务器,Android 上传图片到服务器时将bitmap转换为byte[]最后转换为String...

    1. //上传图片到服务器 Bitmap bitmap = ------;//得到图片 ByteArrayOutputStream out=new ByteArrayOutputStream(); t ...

  8. android之ftp连接服务器,android ftp服务器实现

    通过ApacheFtpServer实现,依赖以下jar包: commons-net-ftp-2.0.jar ftpserver-core-1.0.6.jar log4j-1.2.14.jar mina ...

  9. 构建高性能.NET应用之配置高可用IIS服务器-第四篇 IIS常见问题之:工作进程回收机制(上)

    通过三篇文章的普及,相信大家对IIS应该有了一个基本的了解.那么从本篇文章开始,我们就开始进入IIS一些比较实际的话题:如何配置IIS,使得其性能尽可能的高. 我们在本篇中主要讲述的就是"工 ...

最新文章

  1. Python 获取字符串的第一位和最后一位的字符
  2. 简易git操作 -- 让你的格子绿起来
  3. 聚焦AI落地痛点,纵论跨域学习技术前沿和应用趋势 | CNCC技术论坛
  4. 函数指针——typedef函数指针
  5. MyBatis 传递多个参数
  6. java 哈希算法_选择Java密码算法第1部分-哈希
  7. frp + nginx 配置多人共用的http 内网穿透服务
  8. Android PackageManagerService分析三:卸载APK
  9. Debian系统apt-get build-dep命令
  10. 用Python来实现2~7阶行列式的计算
  11. 万能的json格式化
  12. access中本年度的四月一日_吉林十二中古时孔夫子栽银杏设坛讲学 今日十二中植银杏校园生辉...
  13. word文档如何排版图片
  14. 从小白到鹅厂的通关秘籍(附简历讲解与部分面试题)
  15. 程序员最关注的三大话题,第二个不信你不看
  16. 使用JOL工具直接查看出java对象大小
  17. 广州蓝景分享—Web前端开发培训机构如何选择
  18. [转帖]奋斗5年 从月薪3500到700万!
  19. 三子棋(井字棋)的实现
  20. 网络基础之ACL(访问控制列表)

热门文章

  1. 为什么 Kafka 这么快?
  2. 自带数据线的迷你数显充电宝,春运相亲必备呀
  3. 8.3 折特惠票仅剩 5 天!「2019 嵌入式智能国际大会」全日程大公开!
  4. 支付宝招“找茬”程序员,年薪无上限;谷歌宣布实现“量子霸权”;node.js 13.0.3 发布 | 极客头条...
  5. 小米将开源进行到底!
  6. 你还在抱怨开发工具,为什么不动手优化? | 人物志
  7. 为什么拼多多黄峥和陆奇走到了一起?
  8. 学习 Python 这么多年,掉过的那些安全漏洞
  9. 继去年“技惊四座”之后,腾讯TPG图片格式在应用领域有了新进展
  10. aix ntp 配置_aix下开启ntp服务