黑信 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(); @Override protected 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); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(receiver); } @Override public 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"; @Override public 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() { @Override public 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() { @Override public 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()); } @Override public 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; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); connectorManager = ConnectorManager.getInstance(); new Thread(new Runnable() { @Override public 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(); } @Override public 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() { @Override public 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串转换为map Map<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的进 ...
随机推荐
- Eclipse代码注释模板修改
/** * @ClassName: ${type_name} * @author: <font color="red"><b>ZF</b>< ...
- PHP5的对象复制
今天用yii开发程序,一个bug改了一晚上,最后发现问题出在了对象复制机制上,PHP5之前的对象复制只需要$object_a = $object_b即可,但PHP5这样得到的是浅复制,及指针指向,并不 ...
- jquery 选项卡实现
HTML文件 $(function(){ var $div_li =$("div.tab_menu ul li"); $div_li.click(function(){ $(thi ...
- CLR via C#可空值类型
我们知道,一个值类型的变量永远不可能为null.它总是包含值类型本身.遗憾的是,这在某些情况下会成为问题.例如,设计一个数据库时,可将一个列定义成为一个32位的整数,并映射到FCL的Int32数据类型 ...
- storm supervisor启动报错java.lang.RuntimeException: java.io.EOFException
storm因机器断电或其他异常导致的supervisor意外终止,再次启动时报错: 1. 2013-09-24 09:15:44,361 INFO [main] daemon.supervisor ( ...
- iOS开发——常用宏的定义
有些时候,我们需要将代码简洁化,这样便于读代码.我们可以将一些不变的东东抽取出来,将变化的东西作为参数.定义为宏,这样在写的时候就简单多了. 下面例举了一些常用的宏定义和大家分享: 1. 判断设备的操 ...
- SqlServer将数据库中的表复制到另一个数据库
前述: 文章来自百度经验 操作: 在使用SqlServer的过程中,我们可能需要将表从一个数据库复制到另一个数据库中,今天,为大家介绍这种操作的具体方法及步骤. 复制表结构 1 首先,打开并连接Sql ...
- 触摸事件 - UIControlEvents
首先,UIControlEvents有这个几种: UIControlEventTouchDown = 1 << 0, // on all touch dow ...
- UI基础 - UITabBarController
self.window = [[UIWindow alloc] init]; self.window.frame = [UIScreen mainScreen].bounds; oneViewCont ...
- iOS开发之WKWebView简单使用
iOS开发之WKWebView简单使用 iOS开发之 WKWebVeiw使用 想用UIWebVeiw做的,但是突然想起来在iOS8中出了一个新的WKWebView,算是UIWebVeiw的升级版. ...