最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

IM

运维笔记admin38浏览0评论

IM

IM

1. IM基本概念与原理

1.1. TCP/IP UDP

1.2. 三次握手

1.3. 常见形式

1.4. IM原理

1.5. 注意点

2. 核心概念

2.1. 消息内容_IM服务端接口文档

2.2. 消息内容_Xstream自动生成

2.3. 项目应用:继承基类

2.4. 消息通道-连接对象

2.5. 消息发送

2.6. 消息接收

2.6.1. 监听器

3. 项目功能-Socket

3.1. 模块:启动页面

3.2. 模块:登录

3.3. 模块.好友

3.4. 模块.好友--上线更新

4. 模块:聊天

4.1. 后台Service运行消息接收

5. Provider复习--保存联系人

练习

 

  1. IM基本概念与原理

QQ 微信 陌陌

即时通讯

IM  instant messager

通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,即时获取到消息。

消息通道:由TCP/IP UDP实现的通道。

    1. TCP/IP UDP

TCP/UDP:传输消息的时候,封装上ip信息。

ip

网络上电脑的编号  192.168.10.100

port

网络程序的编号 tomcat 8080

 

TCP

UDP

大文件

64K

可靠

不可靠

面向连接

不面向连接

效率低

效率高

1.打电话 2.运货

1.运货

 

    1. 三次握手

 

 

    1. 常见形式

在线直传

不经过服务器,Peer to Peer

p2p

在线代理

消息经过服务器 中转 到达目标账号

离线代理

消息经过服务器 中转 到达目标账号  对方不在线 消息暂存服务器的数据库,在其上线 再传发

离线扩展

将暂存消息 以其它 邮件 短信 转发给目标账号

 

    1. IM原理

注意事项:消息通道不能断开

  • 用户登录,提交账号密码 经服务端确定
  • 成功以服务端发回 好友信息
  • 消息必须包含 from to content time
  • 由服务器转发给目标账号

    1. 注意点

findViewId

客户端

C++  java

概念理解 含义

Socket 套接字  插头 客户端程序

ServerSocket   插座  服务端程序

消息对象

 

 

  1. 核心概念

自主研发

开源服务器

socket

借助开源

IM服务端接口文档

 

 

    1. 消息内容_IM服务端接口文档

IM服务接口文档:以文档的形式 规定 通讯消息的 字段与格式(xml/json)

消息对象:消息内容+附加字段的封装

xml

json

黑马

 

<name>黑马</name>

{name:黑马}

耗流量

节省流量

扩展性  xml  msn

相对较差

Xstream  将java对象xml互换

Xstream  x=new XStream();

toXml   对象转xml

fromXml   xml转对象

gson 将java 对象json字符串

GSON  gson=new Gson();

toJson

fromJson

不生成get set 会使用效率降低

 

 

    1. 消息内容_Xstream自动生成

Junit

  • junit3/4
  • 功能清单配置
  • 编写测试代码

 

Xstream

  • 创建核心对象
  • 调用toXml 或者fromXml

 

05-21 02:08:07.775: I/System.out(1204): <QQMessage>

05-21 02:08:07.775: I/System.out(1204):   <content>今晚有空没</content>

05-21 02:08:07.775: I/System.out(1204):   <type>chatp2p</type>

05-21 02:08:07.775: I/System.out(1204):   <sendTime>08-141 02:08:07</sendTime>

05-21 02:08:07.775: I/System.out(1204):   <fromNick>老王@qq</fromNick>

05-21 02:08:07.775: I/System.out(1204):   <from>7</from>

05-21 02:08:07.775: I/System.out(1204):   <to>10086</to>

05-21 02:08:07.775: I/System.out(1204):   <fromAvatar>1</fromAvatar>

05-21 02:08:07.775: I/System.out(1204): </QQMessage>

 

    // ① 创建核心对象

       XStream x = new XStream();

       x.alias("QQMessage", QQMessage.class);

       QQMessage msg = new QQMessage();

       msg.type = QQMessageType.MSG_TYPE_CHAT_P2P;

       msg.content = "今晚有空没";

       msg.fromNick = "老王@qq";

       msg.from = 007;

       msg.to = 10086;

       // ② 调用toXml 或者fromXml

       String xml = x.toXML(msg);

       QQMessage m2 = (QQMessage) x.fromXML(xml);

       System.out.println(m2.fromNick);

 

    1. 项目应用:继承基类

public class ProtocalObj {

    public String toXml() {

       XStream x = new XStream();

       x.alias(this.getClass().getSimpleName(), this.getClass());

       // ② 调用toXml 或者fromXml

       return x.toXML(this);

 

    }

 

    public Object fromXml(String xml) {

       XStream x = new XStream();

       x.alias(this.getClass().getSimpleName(), this.getClass());

       // ② 调用toXml 或者fromXml

       return x.fromXML(xml);

    }

 

    public String toJson() {

       Gson gson = new Gson();

       return gson.toJson(this);

 

    }

 

    public Object fromJson(String json) {

       Gson gson = new Gson();

       return gson.fromJson(json, this.getClass());

    }

}

    1.  消息通道-连接对象

消息通道:消息对象传输的通道. 路 桥  1.发送消息  2.接收消息

消息通道

           try {

                  Socket client = new Socket(HOST, PORT);

              } catch (Exception e) {

                  e.printStackTrace();

              }// TODO Auto-generated method stub

 

    1. 消息发送

OutputStream 发送

  |--DataOutputStream

writeUTF

InputStream  接收

  |--DataInputStream

readUTF

 

                  QQMessage msg = new QQMessage();

                  msg.type = QQMessageType.MSG_TYPE_LOGIN;

                  msg.content = "101#test";

                  String xml=msg.toXml();

                  writer.writeUTF(xml);

                  writer.flush();

 

    1. 消息接收

    // 等待消息

                     new Thread() {

                         public void run() {

                            while (true) {

                                try {

                                   String xml = reader.readUTF();

                                  

                                   System.out.println("接收到消息 :"+xml);

                                } catch (IOException e) {

                                   // TODO Auto-generated catch block

                                   e.printStackTrace();

                                }

                            }

                         };

                     }.start();

 

      1. 监听器

监听器:一个接口 含有抽象方法 接收参数

在即时通讯的项目 消息接收器-->抽象方法来处理

开发步骤

  • 申明接口
  • 抽象方法
  • 定义参数
  • 添加方法 移除
  • 参数产生的地方调用
  1. 项目功能-Socket
    1. 模块:启动页面
  1. 继承
  2. 重写
  3. 配置
  4. 打开

 

开发步骤

  • 布局 ImageView
  • 等待3000

 

ThreadUtils.runInThread(new Runnable() {

           @Override

           public void run() {

              try {

                  //检查更新

                  //初始

                  Thread.sleep(3000);

              } catch (InterruptedException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

              }

 

           }

       });

 

    1. 模块:登录

提交账号密码 给服务器验证  接收验证结果编写逻辑

 

ButterKnife 黄油刀

注解开发库

findViewById

@InjectView   set 设置

findViewById  setOnClickLisener

@OnClick

ButterKnife.inject(this);

初始化 xUtils

配置eclipse

apt  annotation process  tool

设置jar

 

开发步骤

  • 布局 TableLayout
  • 事件逻辑

发送

QQMessage msg = new QQMessage();

              msg.type = QQMessageType.MSG_TYPE_LOGIN;

               msg.content = username + "#" + password;

              String xml = msg.toXml();

              if (conn != null) {

                  try {

                     conn.sendMessage(xml);

                  } catch (IOException e) {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

                  }

              }

 

private OnQQMessageReceiveListener listener = new OnQQMessageReceiveListener() {

       @Override

       public void onReceive(QQMessage msg) {

           System.out.println(msg.toXml());

           if (QQMessageType.MSG_TYPE_BUDDY_LIST.equals(msg.type)) {

 

              ThreadUtils.runUIThread(new Runnable() {

 

                  @Override

                  public void run() {

                    

                     MyApp.me=conn;

                     MyApp.username=username;

                     MyApp.account=username+"@qq";

                     Toast.makeText(getBaseContext(), "登录成功", 0).show();

                     startActivity(new Intent(getBaseContext(), MainActivity.class));

                     finish();

                  }

              });

 

           } else {

 

              ThreadUtils.runUIThread(new Runnable() {

 

                  @Override

                  public void run() {

                     Toast.makeText(getBaseContext(), "登录失败", 0).show();

                  }

              });

 

           }

       }

    };

 

    1. 模块.好友

显示所有好友联系人信息,受好友上线/下线的影响

开发步骤

  • 布局 ListView
  • 解析xml --> 集合
  • 创建Adapter
  • 设置给控件

 

private List<QQBuddy> list = new ArrayList<QQBuddy>();

    private ArrayAdapter<QQBuddy> adapter = null;

    private void setAdapter() {

       if (list.size() < 1) {

           return;

       }

       // adapter=new ArrayAdapter<QQBuddy>(上下文,行视图,数据集合);

       adapter = new ArrayAdapter<QQBuddy>(this, 0, list) {

           // 返回视图 显示了指定下标的数据

           @Override

           public View getView(int position, View convertView, ViewGroup parent) {

              ViewHolder holder = null;

              if (convertView == null) {

                  convertView = View.inflate(getBaseContext(), R.layout.item_buddy, null);

                  holder = new ViewHolder(convertView);

                  convertView.setTag(holder);

              }else

              {

                  holder=(ViewHolder) convertView.getTag();

              }

             

              QQBuddy buddy=list.get(position);

              holder.nick.setText(buddy.nick+"");

              holder.account.setText(buddy.account+"@qq");

              return convertView;

           }

       };

       listview.setAdapter(adapter);

    }

 

    static class ViewHolder {

       @InjectView(R.id.head)

       ImageView head;

       @InjectView(R.id.nick)

       TextView nick;

       @InjectView(R.id.account)

       TextView account;

 

       public ViewHolder(View view) {

           ButterKnife.inject(this, view);

       }

    }

    1. 模块.好友--上线更新

@Override

    protected void onDestroy() {

       // TODO Auto-generated method stub

       super.onDestroy();

       MyApp.me.removeOnQQMessageReceiveListener(listener);

    }

    private OnQQMessageReceiveListener listener = new OnQQMessageReceiveListener() {

 

       @Override

       public void onReceive(QQMessage msg) {

 

           if (QQMessageType.MSG_TYPE_BUDDY_LIST.equals(msg.type)) {

              QQBuddyList temp = new QQBuddyList();

              temp = (QQBuddyList) temp.fromXml(msg.content);

              list.clear();

              list.addAll(temp.buddyList);

 

              ThreadUtils.runUIThread(new Runnable() {

 

                  @Override

                  public void run() {

                     setAdapterOrNitify();

                     // 刷新ListView

                  }

              });

           }

 

       }

    };

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

       // TODO Auto-generated method stub

       super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_contact);

       MyApp.me.addOnQQMessageReceiveListener(listener);

  1. 模块:聊天

消息在消息通道中传输,发送+接收

开发步骤

  • 静态UI (界面显示假数据)
  • 假数据换成真数据
  • Service运行消息接收程序

 

Actvity/Fragment

Service

显示界面的控件

不包含界面,运行于后台的隐蔽程序

返回键关闭程序

后台接收消息

 

    1. 后台Service运行消息接收

public class ImService extends Service {

    // 必须使用监听器

    private OnQQMessageReceiveListener listener = new OnQQMessageReceiveListener() {

       @Override

       public void onReceive(final QQMessage msg) {

           if (QQMessageType.MSG_TYPE_CHAT_P2P.equals(msg.type)) {

              // Notification

              ThreadUtils.runUIThread(new Runnable() {

                  @Override

                  public void run() {

                     Toast.makeText(getBaseContext(), "好友消息:" + msg.content, 0).show();

                  }

              });

           }

 

       }

    };

    @Override

    public void onCreate() {

       super.onCreate();

       // Notification

       Toast.makeText(getBaseContext(), "IM后台服务打开", 0).show();

       MyApp.me.addOnQQMessageReceiveListener(listener);

    }

 

    @Override

    public void onDestroy() {

       super.onDestroy();

       MyApp.me.removeOnQQMessageReceiveListener(listener);

    }

 

    @Override

    public IBinder onBind(Intent intent) {

       // TODO Auto-generated method stub

       return null;

    }

 

}

  1. Provider复习--保存联系人

开发步骤

  • 创建Provider 1.继承 2.重写 3.注册 4.使用
  • 设计表结构
  • 建表语句
  • 获取OpenHelper实例
  • 获取数据库实例SqliteDatabase
  • CRUD
  • Junit

 

  <provider

            android:name="com.itheima.im3.provider.ContactProvider"

            android:authorities="com.itheima.im3.provider.ContactProvider" >

        </provider>

 

public class ContactProvider extends ContentProvider {

 

    // Canonical全部类名 com.itheima.im3.core.ContactProvider

 

    private static final String authority = ContactProvider.class.getCanonicalName();

 

    // ① 创建Provider 1.继承 2.重写 3.注册 4.使用

    // ② 设计表结构

    // BaseColumns带id的字段接口

    public static class Contact implements BaseColumns {

       public static final String ACCOUNT = "account";

       public static final String NICK = "nick";

       public static final String AVATAR = "avatar";

       public static final String SORT = "sort";// 拼音

    }

 

    // ③ 建表语句

    public static final String TABLE = "contact";//

    public static final String DB = "contact.db";// 拼

 

    private class MyHelper extends SQLiteOpenHelper {

 

       public MyHelper(Context context) {

           super(context, DB, null, 1);

       }

 

       @Override

       public void onCreate(SQLiteDatabase db) {

           String sql = "create table contact(_id integer auto  increment primary key ,account long ,nick text,avatar integer,sort text)";

 

           db.execSQL(sql);

 

       }

 

    }

 

    private MyHelper mMyHelper = null;

 

    // ④ 获取OpenHelper实例

    // ⑤ 获取数据库实例SqliteDatabase

    // ⑥ CRUD

    // ⑦ Junit

 

    private SQLiteDatabase db = null;

 

    @Override

    public boolean onCreate() {

       if (mMyHelper == null) {

           mMyHelper = new MyHelper(getContext());

       }

       return mMyHelper == null ? false : true;

    }

 

    @Override

    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {

       // TODO Auto-generated method stub

       return null;

    }

 

    @Override

    public String getType(Uri uri) {

       // TODO Auto-generated method stub

       return null;

    }

 

    public static final Uri CONTACT_URI = Uri.parse("content://" + authority + "/" + TABLE);

    private static UriMatcher uris = null;

    private static final int CANTACT = 0;

    static {

       uris = new UriMatcher(UriMatcher.NO_MATCH);

       uris.addURI(authority, TABLE, CANTACT);

    }

 

    // content://authority/contact

    // content://authority/contact/1

    // ContentUris工具 1.uri +id 2. 获取id

    @Override

    public Uri insert(Uri uri, ContentValues values) {

       switch (uris.match(uri)) {

       case CANTACT:

           db = mMyHelper.getWritableDatabase();

           long id = db.insert(TABLE, "", values);

           if (id != -1) {

              uri = ContentUris.withAppendedId(uri, id);

           }

           break;

       }

       return uri;

    }

 

ContentValues record = new ContentValues();

       record.put(ContactProvider.Contact.ACCOUNT, 101);

       record.put(ContactProvider.Contact.NICK, "隔壁老王");

       record.put(ContactProvider.Contact.SORT, "GBLW");

       record.put(ContactProvider.Contact.AVATAR, 0);

       // getContext().getContentResolver().insert(访问地址, 一条记录);

       getContext().getContentResolver().insert(ContactProvider.CONTACT_URI, record);

 

练习

Provider

原理

contact CRUD +test

Chat模块

代码写一遍

应用

OA

客服

Chat

婚恋

医疗

企业级通讯软件

 

 

 

发布评论

评论列表(0)

  1. 暂无评论