整个过程

  1. 首先开启服务器
  2. 打开一个SDK大于4.4的手机---B
  3. 打开一个SDK小于4.4的手机---A
  4. 相互发送一条消息,对方就可以收到,当然这些消息都是通过服务器【转发】过来的
  5.  

MainActivity

  1. /**
  2.  *  Activity启动以后就开启服务,服务开启后就通过ConnectorManager调用Connector中的connect方法对客户端进行认证
  3.  *  认证是通过三次握手完成的,服务器为所有认证的客户端新建一个线程,通过此线程和客户端通讯
  4.  *  当点击发送按钮后,通过ConnectorManager调用Connector中的方法把消息发送到一个阻塞队列中,最终发给服务器
  5.  *  服务器收到消息后将其【转发】给指定客户端的Connector的阻塞队列中,客户端又通过listener.pushData(text)转发消息
  6.  *  由于ConnectorManager注册了Connector的回调,ConnectorService又注册了ConnectorManager的回调
  7.  *  所以最终调用的是ConnectorService的回调方法pushData(data) ,而此方法又通过发送一条广播将消息转发出去
  8.  *  此广播会被PushReceiver接收到,因为其是在MainActivity注册的,所以最终MainActivity也收到了服务器转发过来的消息
  9.  */
  10. public class MainActivity extends Activity implements OnClickListener {
  11.     private EditText et;
  12.     private Button send;
  13.     private PushReceiver receiver = new PushReceiver();
  14.     @Override
  15.     protected void onCreate(Bundle savedInstanceState) {
  16.         super.onCreate(savedInstanceState);
  17.         setContentView(R.layout.activity_main);
  18.         et = (EditText) findViewById(R.id.et);
  19.         send = (Button) findViewById(R.id.send);
  20.         send.setOnClickListener(this);
  21.         //Activity启动以后就开启服务
  22.         startService(new Intent(this, ConnectorService.class));
  23.         //在代码中动态注册广播,这种类型的广播不是常驻型广播,也就是说广播跟随程序的生命周期
  24.         IntentFilter filter = new IntentFilter();
  25.         filter.addAction(PushReceiver.ACTION_TEXT);
  26.         registerReceiver(receiver, filter);
  27.     }
  28.     @Override
  29.     protected void onDestroy() {
  30.         super.onDestroy();
  31.         unregisterReceiver(receiver);
  32.     }
  33.     @Override
  34.     public void onClick(View v) {
  35.         switch (v.getId()) {
  36.         case R.id.send:
  37.             sendMessage();
  38.             break;
  39.         default:
  40.             break;
  41.         }
  42.     }
  43.     public void sendMessage() {
  44.         final String content = et.getText().toString().trim();
  45.         if (TextUtils.isEmpty(content)) return;
  46.         String sender = null;
  47.         String token = null;
  48.         String receiver = null;
  49.         if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
  50.             sender = "B";
  51.             receiver = "A";
  52.             token = "B";
  53.         } else {
  54.             sender = "A";
  55.             token = "A";
  56.             receiver = "B";
  57.         }
  58.         Request request = new TextRequest(sender, token, receiver, content);
  59.         ConnectorManager.getInstance().putRequest(request);
  60.     }
  61. }
  62.  

广播

  1. public class PushReceiver extends BroadcastReceiver {
  2.     /**发送文本信息的事件*/
  3.     public static final String ACTION_TEXT = "com.bqt.action.text";
  4.     public static final String DATA_KEY = "data";
  5.     @Override
  6.     public void onReceive(Context context, Intent intent) {
  7.         String action = intent.getAction();
  8.         Log.d("activity", "receive");
  9.         if (PushReceiver.ACTION_TEXT.equals(action)) {
  10.             String text = intent.getStringExtra(PushReceiver.DATA_KEY);
  11.             Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
  12.         }
  13.     }
  14. }
  15.  

业务bean

  1. /**用一个类把与Socket相关的连接、发送消息、断开连接等方法抽离出来,并通过回调方式把结果返回*/
  2. public class Connector {
  3.     public static final String DST_NAME = "192.168.31.165";
  4.     public static final int DST_PORT = 10002;
  5.     private Socket client;
  6.     //有界阻塞队列,当容量满时往BlockingQueue中添加数据时会阻塞,当容量为空时取元素操作会阻塞。
  7.     private ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(8);
  8.     private ConnectorListener listener;
  9.     /**连接*/
  10.     public void connect() {
  11.         try {
  12.             // 三次握手
  13.             if (client == null || client.isClosed()) client = new Socket(DST_NAME, DST_PORT);
  14.             new Thread(new Runnable() {
  15.                 @Override
  16.                 public void run() {
  17.                     // 数据通讯
  18.                     OutputStream os;
  19.                     try {
  20.                         os = client.getOutputStream();
  21.                         // os.write(content.getBytes());
  22.                         while (true) {
  23.                             String content = queue.take();
  24.                             os.write(content.getBytes());
  25.                         }
  26.                     } catch (Exception e) {
  27.                         e.printStackTrace();
  28.                     }
  29.                 }
  30.             }).start();
  31.             new Thread(new Runnable() {
  32.                 @Override
  33.                 public void run() {
  34.                     try {
  35.                         InputStream is = client.getInputStream();
  36.                         byte[] buffer = new byte[1024];
  37.                         int len = -1;
  38.                         while ((len = is.read(buffer)) != -1) {
  39.                             final String text = new String(buffer, 0, len);
  40.                             System.out.println("服务器转发的消息 : " + text);
  41.                             //获取服务器向客户端转发的消息
  42.                             if (listener != null) listener.pushData(text);
  43.                         }
  44.                     } catch (Exception e) {
  45.                         e.printStackTrace();
  46.                     }
  47.                 }
  48.             }).start();
  49.         } catch (Exception e) {
  50.             e.printStackTrace();
  51.         }
  52.     }
  53.     /**认证*/
  54.     public void auth(String auth) {
  55.         putRequest(auth);
  56.     }
  57.     /**发送消息*/
  58.     public void putRequest(String content) {
  59.         try {
  60.             queue.put(content);
  61.         } catch (InterruptedException e) {
  62.             e.printStackTrace();
  63.         }
  64.     }
  65.     /**断开连接*/
  66.     public void disconnect() {
  67.         try {
  68.             if (client != null && !client.isClosed()) {
  69.                 client.close();
  70.                 client = null;
  71.             }
  72.         } catch (IOException e) {
  73.             e.printStackTrace();
  74.         }
  75.     }
  76.     public void setConnectorListener(ConnectorListener listener) {
  77.         this.listener = listener;
  78.     }
  79. }
  80.  

接口

  1. public interface ConnectorListener {
  2.     void pushData(String data);
  3. }
  4.  

接口实现类

  1. /**管理Connector的方法,目的:隐藏实现细节,简化对外暴露的方法*/
  2. public class ConnectorManager implements ConnectorListener {
  3.     private static ConnectorManager instance;
  4.     private Connector connector;
  5.     private ConnectorListener listener;
  6.     private ConnectorManager() {
  7.     }
  8.     public static ConnectorManager getInstance() {
  9.         if (instance == null) {
  10.             synchronized (ConnectorManager.class) {
  11.                 if (instance == null) instance = new ConnectorManager();
  12.             }
  13.         }
  14.         return instance;
  15.     }
  16.     /**连接、注册监听、认证*/
  17.     public void connnect(AuthRequest auth) {
  18.         connector = new Connector();
  19.         connector.setConnectorListener(this);
  20.         connector.connect();
  21.         connector.auth(auth.getData());
  22.     }
  23.     /**发送消息*/
  24.     public void putRequest(Request request) {
  25.         connector.putRequest(request.getData());
  26.     }
  27.     @Override
  28.     public void pushData(String data) {
  29.         if (listener != null) listener.pushData(data);
  30.     }
  31.     public void setConnectorListener(ConnectorListener listener) {
  32.         this.listener = listener;
  33.     }
  34. }
  35.  

接口实现类-后台服务

  1. /**
  2.  * 作用①:Activity启动以后就开启服务通过ConnectorManager调用Connector中的connect方法对客户端进行认证
  3.  * 作用②:客户端收到服务器转发过来的消息后通过ConnectorService的pushData通过发送一条广播将消息转发出去
  4.  * 注意:为简化代码,若客户端(手机)SDK版本小于4.4则定义为A手机,否则就定义为B手机,请演示时一定注意!
  5.  */
  6. public class ConnectorService extends Service implements ConnectorListener {
  7.     private ConnectorManager connectorManager;
  8.     @Override
  9.     public IBinder onBind(Intent intent) {
  10.         return null;
  11.     }
  12.     @Override
  13.     public void onCreate() {
  14.         super.onCreate();
  15.         connectorManager = ConnectorManager.getInstance();
  16.         new Thread(new Runnable() {
  17.             @Override
  18.             public void run() {
  19.                 connectorManager.setConnectorListener(ConnectorService.this);
  20.                 //认证
  21.                 AuthRequest request = null;
  22.                 //当前SDK版本大于4.4---暂时这么区分两部手机,实际肯定不是这么搞得
  23.                 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) request = new AuthRequest("B", "B");
  24.                 else request = new AuthRequest("A", "A");
  25.                 connectorManager.connnect(request);
  26.             }
  27.         }).start();
  28.     }
  29.     @Override
  30.     public void pushData(String data) {
  31.         Log.d("coreService", "data : " + data);
  32.         Intent intent = new Intent();
  33.         intent.setAction(PushReceiver.ACTION_TEXT);
  34.         intent.putExtra(PushReceiver.DATA_KEY, data);
  35.         sendBroadcast(intent);
  36.     }
  37. }
  38.  

服务器代码

  1. public class TCPServer {
  2.     private static final int port = 10002;
  3.     /**保存并标记所有建立连接的客户端*/
  4.     private static Map<String, Socket> clients = new LinkedHashMap<String, Socket>();
  5.     public static void main(String[] args) {
  6.         try {
  7.             ServerSocket server = new ServerSocket(port);
  8.             while (true) {
  9.                 System.out.println("准备阻塞...");
  10.                 // 获得客户端连接,阻塞式方法
  11.                 final Socket client = server.accept();
  12.                 System.out.println("阻塞完成...");
  13.                 //每连接一个客户端就新建一个线程
  14.                 new Thread(new Runnable() {
  15.                     @Override
  16.                     public void run() {
  17.                         try {
  18.                             // 获取客户端的输入流,也即客户端发送的数据。
  19.                             //注意输入流和输出流相对于内存设备而言,将外设中的数据读取到内存中就是输入
  20.                             InputStream is = client.getInputStream();
  21.                             // 输出流,给客户端写数据
  22.                             OutputStream os = client.getOutputStream();
  23.                             byte[] buffer = new byte[1024];
  24.                             int len = -1;
  25.                             System.out.println("准备read...");
  26.                             while ((len = is.read(buffer)) != -1) {
  27.                                 System.out.println("read完成...");
  28.                                 String text = new String(buffer, 0, len);
  29.                                 System.out.println(text);
  30.                                 //将客户端发送的json串转换为map
  31.                                 Map<String, String> map = new Gson().fromJson(text, new TypeToken<Map<String, String>>() {
  32.                                 }.getType());
  33.                                 String type = map.get("type");
  34.                                 if ("request".equals(type)) {
  35.                                     String action = map.get("action");
  36.                                     if ("auth".equals(action)) {
  37.                                         // 认证消息处理
  38.                                         String sender = map.get("sender");
  39.                                         System.out.println(sender + "认证");
  40.                                         // 放到容器当中
  41.                                         clients.put(sender, client);
  42.                                     } else if ("text".equals(action)) {
  43.                                         // 文本消息
  44.                                         String sender = map.get("sender");//客户端写死了
  45.                                         String receiver = map.get("receiver");
  46.                                         String content = map.get("content");
  47.                                         Socket s = clients.get(receiver);
  48.                                         if (!= null) {// 在线
  49.                                             OutputStream output = s.getOutputStream();
  50.                                             output.write(content.getBytes());
  51.                                         } else {    // 离线
  52.                                         }
  53.                                     }
  54.                                 } else System.out.println("格式错误");
  55.                             }
  56.                         } catch (Exception e) {
  57.                             e.printStackTrace();
  58.                         }
  59.                     }
  60.                 }).start();
  61.             }
  62.         } catch (Exception e) {
  63.             e.printStackTrace();
  64.         }
  65.     }
  66. }
  67.  

附件列表

黑信 socket即时通讯 示例的更多相关文章

  1. TCP UDP Socket 即时通讯 API 示例 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. C#上位机之—WinForm实现Socket异步通讯示例

    工作中常用到的一些知识点,总是用完就忘,第一次尝试用博客记录下来,以备后用: Socket通讯,Socket(套接字)是基于TCP/IP通讯方式的封装好的类,调用时需要添加下面的服务引用: using ...

  3. NetCore WebSocket 即时通讯示例

    1.新建Netcore Web项目 2.创建简易通讯协议 public class MsgTemplate { public string SenderID { get; set; } public ...

  4. wpf socket 简单通讯示例

    源码下载地址:https://github.com/lizhiqiang0204/WPF-Socket 效果如下:

  5. node.js和socket.io纯js实现的即时通讯实例分享

    在这个例子中,其实node.js并没有真正起到服务器的作用,因为我们这里可以直接运行client.html文件,而不用输入url请求,当 然,要想输入url请求页面内容还需要加入请求静态文件的代码.这 ...

  6. iOS开发之即时通讯之Socket(AsyncSocket)

    1.AsyncSocket介绍 如果需要在项目中像QQ微信一样做到即时通讯,必须使用socket通讯. iOS中Socket编程的方式: BSD Socket: BSD Socket 是UNIX系统中 ...

  7. Android查缺补漏(IPC篇)-- 进程间通讯之Socket简介及示例

    本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8425736.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...

  8. java socket 模拟im 即时通讯

    自己想了一下怎么实现,就写了,没有深究是否合理.更多处理没有写下去,例如收件人不在线,应该保存在数据库,等下一次连接的时候刷新map,再把数据发送过去,图片发送也没有做,也没有用json格式 sock ...

  9. iOS:即时通讯之<了解篇 SocKet>

    什么是socket? 计算机专业术语就是: 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket.Socket的英文原义是“孔”或“插座”.作为BSD UNIX的进 ...

随机推荐

  1. Eclipse代码注释模板修改

    /** * @ClassName: ${type_name} * @author: <font color="red"><b>ZF</b>< ...

  2. PHP5的对象复制

    今天用yii开发程序,一个bug改了一晚上,最后发现问题出在了对象复制机制上,PHP5之前的对象复制只需要$object_a = $object_b即可,但PHP5这样得到的是浅复制,及指针指向,并不 ...

  3. jquery 选项卡实现

    HTML文件 $(function(){ var $div_li =$("div.tab_menu ul li"); $div_li.click(function(){ $(thi ...

  4. CLR via C#可空值类型

    我们知道,一个值类型的变量永远不可能为null.它总是包含值类型本身.遗憾的是,这在某些情况下会成为问题.例如,设计一个数据库时,可将一个列定义成为一个32位的整数,并映射到FCL的Int32数据类型 ...

  5. storm supervisor启动报错java.lang.RuntimeException: java.io.EOFException

    storm因机器断电或其他异常导致的supervisor意外终止,再次启动时报错: 1. 2013-09-24 09:15:44,361 INFO [main] daemon.supervisor ( ...

  6. iOS开发——常用宏的定义

    有些时候,我们需要将代码简洁化,这样便于读代码.我们可以将一些不变的东东抽取出来,将变化的东西作为参数.定义为宏,这样在写的时候就简单多了. 下面例举了一些常用的宏定义和大家分享: 1. 判断设备的操 ...

  7. SqlServer将数据库中的表复制到另一个数据库

    前述: 文章来自百度经验 操作: 在使用SqlServer的过程中,我们可能需要将表从一个数据库复制到另一个数据库中,今天,为大家介绍这种操作的具体方法及步骤. 复制表结构 1 首先,打开并连接Sql ...

  8. 触摸事件 - UIControlEvents

    首先,UIControlEvents有这个几种: UIControlEventTouchDown           = 1 <<  0,      // on all touch dow ...

  9. UI基础 - UITabBarController

    self.window = [[UIWindow alloc] init]; self.window.frame = [UIScreen mainScreen].bounds; oneViewCont ...

  10. iOS开发之WKWebView简单使用

    iOS开发之WKWebView简单使用   iOS开发之 WKWebVeiw使用 想用UIWebVeiw做的,但是突然想起来在iOS8中出了一个新的WKWebView,算是UIWebVeiw的升级版. ...