黑信 socket即时通讯 示例
整个过程
首先开启服务器打开一个SDK大于4.4的手机---B
打开一个SDK小于4.4的手机---A
相互发送一条消息,对方就可以收到,当然这些消息都是通过服务器【转发】过来的
![]()
![]()
MainActivity
/*** Activity启动以后就开启服务,服务开启后就通过ConnectorManager调用Connector中的connect方法对客户端进行认证* 认证是通过三次握手完成的,服务器为所有认证的客户端新建一个线程,通过此线程和客户端通讯* 当点击发送按钮后,通过ConnectorManager调用Connector中的方法把消息发送到一个阻塞队列中,最终发给服务器* 服务器收到消息后将其【转发】给指定客户端的Connector的阻塞队列中,客户端又通过listener.pushData(text)转发消息* 由于ConnectorManager注册了Connector的回调,ConnectorService又注册了ConnectorManager的回调* 所以最终调用的是ConnectorService的回调方法pushData(data) ,而此方法又通过发送一条广播将消息转发出去* 此广播会被PushReceiver接收到,因为其是在MainActivity注册的,所以最终MainActivity也收到了服务器转发过来的消息*/public class MainActivity extends Activity implements OnClickListener {private EditText et;private Button send;private PushReceiver receiver = new PushReceiver();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et = (EditText) findViewById(R.id.et);send = (Button) findViewById(R.id.send);send.setOnClickListener(this);//Activity启动以后就开启服务startService(new Intent(this, ConnectorService.class));//在代码中动态注册广播,这种类型的广播不是常驻型广播,也就是说广播跟随程序的生命周期IntentFilter filter = new IntentFilter();filter.addAction(PushReceiver.ACTION_TEXT);registerReceiver(receiver, filter);}@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(receiver);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.send:sendMessage();break;default:break;}}public void sendMessage() {final String content = et.getText().toString().trim();if (TextUtils.isEmpty(content)) return;String sender = null;String token = null;String receiver = null;if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {sender = "B";receiver = "A";token = "B";} else {sender = "A";token = "A";receiver = "B";}Request request = new TextRequest(sender, token, receiver, content);ConnectorManager.getInstance().putRequest(request);}}
广播
public class PushReceiver extends BroadcastReceiver {/**发送文本信息的事件*/public static final String ACTION_TEXT = "com.bqt.action.text";public static final String DATA_KEY = "data";@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();Log.d("activity", "receive");if (PushReceiver.ACTION_TEXT.equals(action)) {String text = intent.getStringExtra(PushReceiver.DATA_KEY);Toast.makeText(context, text, Toast.LENGTH_SHORT).show();}}}
业务bean
/**用一个类把与Socket相关的连接、发送消息、断开连接等方法抽离出来,并通过回调方式把结果返回*/public class Connector {public static final String DST_NAME = "192.168.31.165";public static final int DST_PORT = 10002;private Socket client;//有界阻塞队列,当容量满时往BlockingQueue中添加数据时会阻塞,当容量为空时取元素操作会阻塞。private ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(8);private ConnectorListener listener;/**连接*/public void connect() {try {// 三次握手if (client == null || client.isClosed()) client = new Socket(DST_NAME, DST_PORT);new Thread(new Runnable() {@Overridepublic void run() {// 数据通讯OutputStream os;try {os = client.getOutputStream();// os.write(content.getBytes());while (true) {String content = queue.take();os.write(content.getBytes());}} catch (Exception e) {e.printStackTrace();}}}).start();new Thread(new Runnable() {@Overridepublic void run() {try {InputStream is = client.getInputStream();byte[] buffer = new byte[1024];int len = -1;while ((len = is.read(buffer)) != -1) {final String text = new String(buffer, 0, len);System.out.println("服务器转发的消息 : " + text);//获取服务器向客户端转发的消息if (listener != null) listener.pushData(text);}} catch (Exception e) {e.printStackTrace();}}}).start();} catch (Exception e) {e.printStackTrace();}}/**认证*/public void auth(String auth) {putRequest(auth);}/**发送消息*/public void putRequest(String content) {try {queue.put(content);} catch (InterruptedException e) {e.printStackTrace();}}/**断开连接*/public void disconnect() {try {if (client != null && !client.isClosed()) {client.close();client = null;}} catch (IOException e) {e.printStackTrace();}}public void setConnectorListener(ConnectorListener listener) {this.listener = listener;}}
接口
public interface ConnectorListener {void pushData(String data);}
接口实现类
/**管理Connector的方法,目的:隐藏实现细节,简化对外暴露的方法*/public class ConnectorManager implements ConnectorListener {private static ConnectorManager instance;private Connector connector;private ConnectorListener listener;private ConnectorManager() {}public static ConnectorManager getInstance() {if (instance == null) {synchronized (ConnectorManager.class) {if (instance == null) instance = new ConnectorManager();}}return instance;}/**连接、注册监听、认证*/public void connnect(AuthRequest auth) {connector = new Connector();connector.setConnectorListener(this);connector.connect();connector.auth(auth.getData());}/**发送消息*/public void putRequest(Request request) {connector.putRequest(request.getData());}@Overridepublic void pushData(String data) {if (listener != null) listener.pushData(data);}public void setConnectorListener(ConnectorListener listener) {this.listener = listener;}}
接口实现类-后台服务
/*** 作用①:Activity启动以后就开启服务通过ConnectorManager调用Connector中的connect方法对客户端进行认证* 作用②:客户端收到服务器转发过来的消息后通过ConnectorService的pushData通过发送一条广播将消息转发出去* 注意:为简化代码,若客户端(手机)SDK版本小于4.4则定义为A手机,否则就定义为B手机,请演示时一定注意!*/public class ConnectorService extends Service implements ConnectorListener {private ConnectorManager connectorManager;@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();connectorManager = ConnectorManager.getInstance();new Thread(new Runnable() {@Overridepublic void run() {connectorManager.setConnectorListener(ConnectorService.this);//认证AuthRequest request = null;//当前SDK版本大于4.4---暂时这么区分两部手机,实际肯定不是这么搞得if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) request = new AuthRequest("B", "B");else request = new AuthRequest("A", "A");connectorManager.connnect(request);}}).start();}@Overridepublic void pushData(String data) {Log.d("coreService", "data : " + data);Intent intent = new Intent();intent.setAction(PushReceiver.ACTION_TEXT);intent.putExtra(PushReceiver.DATA_KEY, data);sendBroadcast(intent);}}
服务器代码
public class TCPServer {private static final int port = 10002;/**保存并标记所有建立连接的客户端*/private static Map<String, Socket> clients = new LinkedHashMap<String, Socket>();public static void main(String[] args) {try {ServerSocket server = new ServerSocket(port);while (true) {System.out.println("准备阻塞...");// 获得客户端连接,阻塞式方法final Socket client = server.accept();System.out.println("阻塞完成...");//每连接一个客户端就新建一个线程new Thread(new Runnable() {@Overridepublic void run() {try {// 获取客户端的输入流,也即客户端发送的数据。//注意输入流和输出流相对于内存设备而言,将外设中的数据读取到内存中就是输入InputStream is = client.getInputStream();// 输出流,给客户端写数据OutputStream os = client.getOutputStream();byte[] buffer = new byte[1024];int len = -1;System.out.println("准备read...");while ((len = is.read(buffer)) != -1) {System.out.println("read完成...");String text = new String(buffer, 0, len);System.out.println(text);//将客户端发送的json串转换为mapMap<String, String> map = new Gson().fromJson(text, new TypeToken<Map<String, String>>() {}.getType());String type = map.get("type");if ("request".equals(type)) {String action = map.get("action");if ("auth".equals(action)) {// 认证消息处理String sender = map.get("sender");System.out.println(sender + "认证");// 放到容器当中clients.put(sender, client);} else if ("text".equals(action)) {// 文本消息String sender = map.get("sender");//客户端写死了String receiver = map.get("receiver");String content = map.get("content");Socket s = clients.get(receiver);if (s != null) {// 在线OutputStream output = s.getOutputStream();output.write(content.getBytes());} else { // 离线}}} else System.out.println("格式错误");}} catch (Exception e) {e.printStackTrace();}}}).start();}} catch (Exception e) {e.printStackTrace();}}}
附件列表
黑信 socket即时通讯 示例的更多相关文章
- TCP UDP Socket 即时通讯 API 示例 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- C#上位机之—WinForm实现Socket异步通讯示例
工作中常用到的一些知识点,总是用完就忘,第一次尝试用博客记录下来,以备后用: Socket通讯,Socket(套接字)是基于TCP/IP通讯方式的封装好的类,调用时需要添加下面的服务引用: using ...
- NetCore WebSocket 即时通讯示例
1.新建Netcore Web项目 2.创建简易通讯协议 public class MsgTemplate { public string SenderID { get; set; } public ...
- wpf socket 简单通讯示例
源码下载地址:https://github.com/lizhiqiang0204/WPF-Socket 效果如下:
- node.js和socket.io纯js实现的即时通讯实例分享
在这个例子中,其实node.js并没有真正起到服务器的作用,因为我们这里可以直接运行client.html文件,而不用输入url请求,当 然,要想输入url请求页面内容还需要加入请求静态文件的代码.这 ...
- iOS开发之即时通讯之Socket(AsyncSocket)
1.AsyncSocket介绍 如果需要在项目中像QQ微信一样做到即时通讯,必须使用socket通讯. iOS中Socket编程的方式: BSD Socket: BSD Socket 是UNIX系统中 ...
- Android查缺补漏(IPC篇)-- 进程间通讯之Socket简介及示例
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8425736.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- java socket 模拟im 即时通讯
自己想了一下怎么实现,就写了,没有深究是否合理.更多处理没有写下去,例如收件人不在线,应该保存在数据库,等下一次连接的时候刷新map,再把数据发送过去,图片发送也没有做,也没有用json格式 sock ...
- iOS:即时通讯之<了解篇 SocKet>
什么是socket? 计算机专业术语就是: 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket.Socket的英文原义是“孔”或“插座”.作为BSD UNIX的进 ...
随机推荐
- JavaScript 框架比较
显著增强 JavaScript 开发的框架概览 Joe Lennon, 软件开发人员, 自由职业者 简介: 现代 Web 站点和 Web 应用程序倾向于依赖大量客户端 JavaScript 来提供丰富 ...
- underscorejs-min学习
2.16 min 2.16.1 语法: _.min(list, [iteratee], [context]) 2.16.2 说明: 返回list中的最小值. list为集合,数组.对象.字符串或arg ...
- 88 Merge Sorted Array(归并排序Easy)
题目意思:num1和num2均为递增数组,对其进行递增排序存到num1中 class Solution { public: void merge(vector<int>& nums ...
- struts1、ajax、jquery、json简单实例
1.页面ajax代码,使用$.ajax,获得json对象后each $.ajax({ type:"GET", url:ctx + "/uploadImg.do" ...
- [Python笔记]第十一篇:面向对象
以上就是本节对于面向对象初级知识的介绍,总结如下: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用 对象,根据模板创建的实例(即 ...
- iOS程序-UIScrollView的基本使用
iOS程序-UIScrollView的基本使用 scrollView的几个属性contentSize contentOffset contentInset 1.不能向上滑动很可能是因为contentS ...
- nil、Nil、NULL与NSNull的区别--备用
我们来分别介绍一下这四种类型: 一.nil 我们给对象赋值时一般会使用object = nil,表示我想把这个对象释放掉: 或者对象由于某种原因,经过多次release,于是对象引用计数器为0了,系统 ...
- Android Service 简介
Service是Android系统中的一种组件,它跟Activity的级别差不多,但是它不能自己运行,只能后台运行,并且可以和其他组件进行交互.Service是没有界面的长生命周期的代码.Servic ...
- 手机Android音视频采集与直播推送,实现单兵、移动监控类应用
从安卓智能手机.平板,到可穿戴的Android Ware.眼镜.手表.再到Android汽车.智能家居.电视,甚至最近看新闻,日本出的几款机器人都是Android系统的,再把目光放回监控行业,传统监控 ...
- 转:Redis作者谈Redis应用场景
毫无疑问,Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多变的数据结构和数据操作,为不同的大象 ...
打开一个SDK大于4.4的手机---B
打开一个SDK小于4.4的手机---A
相互发送一条消息,对方就可以收到,当然这些消息都是通过服务器【转发】过来的