标签:周期性 协议 cookies enable sync error: tools upd repr
前言
关于我和WebSocket的缘:我从大二在计算机网络课上听老师讲过之后,第一次使用就到了毕业之后的第一份工作。直到最近换了工作,到了一家是含有IM社交聊天功能的app的时候,我觉得我现在可以谈谈我对WebSocket/Socket的一些看法了。要想做IM聊天app,就不得不理解WebSocket和Socket的原理了,听我一一道来。
目录
1.WebSocket使用场景
2.WebSocket诞生由来
3.谈谈WebSocket协议原理
4.WebSocket 和 Socket的区别与联系
5.iOS平台有哪些WebSocket和Socket的开源框架
6.iOS平台如何实现WebSocket协议
一.WebSocket的使用场景
1.社交聊天
最著名的就是微信,QQ,这一类社交聊天的app。这一类聊天app的特点是低延迟,高即时。即时是这里面要求最高的,如果有一个紧急的事情,通过IM软件通知你,假设网络环境良好的情况下,这条message还无法立即送达到你的客户端上,紧急的事情都结束了,你才收到消息,那么这个软件肯定是失败的。
2.弹幕
说到这里,大家一定里面想到了A站和B站了。确实,他们的弹幕一直是一种特色。而且弹幕对于一个视频来说,很可能弹幕才是精华。发弹幕需要实时显示,也需要和聊天一样,需要即时。
3.多玩家游戏
4.协同编辑
现在很多开源项目都是分散在世界各地的开发者一起协同开发,此时就会用到版本控制系统,比如Git,SVN去合并冲突。但是如果有一份文档,支持多人实时在线协同编辑,那么此时就会用到比如WebSocket了,它可以保证各个编辑者都在编辑同一个文档,此时不需要用到Git,SVN这些版本控制,因为在协同编辑界面就会实时看到对方编辑了什么,谁在修改哪些段落和文字。
5.股票基金实时报价
金融界瞬息万变——几乎是每毫秒都在变化。如果采用的网络架构无法满足实时性,那么就会给客户带来巨大的损失。几毫秒钱股票开始大跌,几秒以后才刷新数据,一秒钟的时间内,很可能用户就已经损失巨大财产了。
6.体育实况更新
全世界的球迷,体育爱好者特别多,当然大家在关心自己喜欢的体育活动的时候,比赛实时的赛况是他们最最关心的事情。这类新闻中最好的体验就是利用Websocket达到实时的更新!
7.视频会议/聊天
视频会议并不能代替和真人相见,但是他能让分布在全球天涯海角的人聚在电脑前一起开会。既能节省大家聚在一起路上花费的时间,讨论聚会地点的纠结,还能随时随地,只要有网络就可以开会。
8.基于位置的应用
越来越多的开发者借用移动设备的GPS功能来实现他们基于位置的网络应用。如果你一直记录用户的位置(比如运行应用来记录运动轨迹),你可以收集到更加细致化的数据。
9.在线教育
在线教育近几年也发展迅速。优点很多,免去了场地的限制,能让名师的资源合理的分配给全国各地想要学习知识的同学手上,Websocket是个不错的选择,可以视频聊天、即时聊天以及其与别人合作一起在网上讨论问题...
10.智能家居
这也是我一毕业加入的一个伟大的物联网智能家居的公司。考虑到家里的智能设备的状态必须需要实时的展现在手机app客户端上,毫无疑问选择了Websocket。
11.总结
从上面我列举的这些场景来看,一个共同点就是,高实时性!
二.WebSocket诞生由来
1.最开始的轮询Polling阶段
这种方式下,是不适合获取实时信息的,客户端和服务器之间会一直进行连接,每隔一段时间就询问一次。客户端会轮询,有没有新消息。这种方式连接数会很多,一个接受,一个发送。而且每次发送请求都会有Http的Header,会很耗流量,也会消耗CPU的利用率。
2.改进版的长轮询Long polling阶段
长轮询是对轮询的改进版,客户端发送HTTP给服务器之后,有没有新消息,如果没有新消息,就一直等待。当有新消息的时候,才会返回给客户端。在某种程度上减小了网络带宽和CPU利用率等问题。但是这种方式还是有一种弊端:例如假设服务器端的数据更新速度很快,服务器在传送一个数据包给客户端后必须等待客户端的下一个Get请求到来,才能传递第二个更新的数据包给客户端,那么这样的话,客户端显示实时数据最快的时间为2×RTT(往返时间),而且如果在网络拥塞的情况下,这个时间用户是不能接受的,比如在股市的的报价上。另外,由于http数据包的头部数据量往往很大(通常有400多个字节),但是真正被服务器需要的数据却很少(有时只有10个字节左右),这样的数据包在网络上周期性的传输,难免对网络带宽是一种浪费。
3.WebSocket诞生
现在急需的需求是能支持客户端和服务器端的双向通信,而且协议的头部又没有HTTP的Header那么大,于是,Websocket就诞生了!
上图就是Websocket和Polling的区别,从图中可以看到Polling里面客户端发送了好多Request,而下图,只有一个Upgrade,非常简洁高效。至于消耗方面的比较就要看下图了
上图中,我们先看蓝色的柱状图,是Polling轮询消耗的流量,
Use case A: 1,000 clients polling every second: Network throughput is (871 x 1,000) = 871,000 bytes = 6,968,000 bits per second (6.6 Mbps)
Use case B: 10,000 clients polling every second: Network throughput is (871 x 10,000) = 8,710,000 bytes = 69,680,000 bits per second (66 Mbps)
Use case C: 100,000 clients polling every 1 second: Network throughput is (871 x 100,000) = 87,100,000 bytes = 696,800,000 bits per second (665 Mbps)
而Websocket的Frame是 just two bytes of overhead instead of 871,仅仅用2个字节就代替了轮询的871字节!
Use case A: 1,000 clients receive 1 message per second: Network throughput is (2 x 1,000) = 2,000 bytes = 16,000 bits per second (0.015 Mbps)
Use case B: 10,000 clients receive 1 message per second: Network throughput is (2 x 10,000) = 20,000 bytes = 160,000 bits per second (0.153 Mbps)
Use case C: 100,000 clients receive 1 message per second: Network throughput is (2 x 100,000) = 200,000 bytes = 1,600,000 bits per second (1.526 Mbps)
相同的每秒客户端轮询的次数,当次数高达10W/s的高频率次数的时候,Polling轮询需要消耗665Mbps,而Websocket仅仅只花费了1.526Mbps,将近435倍!!
三.谈谈WebSocket协议原理
Websocket是应用层第七层上的一个应用层协议,它必须依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 TCP 通道传输,与 HTTP 无关了。
Websocket的数据传输是frame形式传输的,比如会将一条消息分为几个frame,按照先后顺序传输出去。这样做会有几个好处:
1)大数据的传输可以分片传输,不用考虑到数据大小导致的长度标志位不足够的情况。
2)和http的chunk一样,可以边生成数据边传递消息,即提高传输效率。
四.WebSocket 和 Socket的区别与联系
首先,Socket 其实并不是一个协议。它工作在 OSI 模型会话层(第5层),是为了方便大家直接使用更底层协议(一般是 TCP 或 UDP )而存在的一个抽象层。Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API)。
Socket通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄。网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket,一个Socket由一个IP地址和一个端口号唯一确定。应用程序通常通过”套接字”向网络发出请求或者应答网络请求。
Socket在通讯过程中,服务端监听某个端口是否有连接请求,客户端向服务端发送连接请求,服务端收到连接请求向客户端发出接收消息,这样一个连接就建立起来了。客户端和服务端也都可以相互发送消息与对方进行通讯,直到双方连接断开。
所以基于WebSocket和基于Socket都可以开发出IM社交聊天类的app
五.iOS平台有哪些WebSocket和Socket的开源框架
Socket开源框架有:CocoaAsyncSocket,socketio/socket.io-client-swift
WebSocket开源框架有:facebook/SocketRocket,tidwall/SwiftWebSocket
六.iOS平台如何实现WebSocket协议
Talk is cheap。Show me the code ——Linus Torvalds
我们今天来看看facebook/SocketRocket的实现方法
首先这是SRWebSocket定义的一些成员变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@property (nonatomic, weak) id delegate;
@property (nonatomic, strong) dispatch_queue_t delegateDispatchQueue;
@property (nonatomic, strong) NSOperationQueue *delegateOperationQueue;
@property (nonatomic, readonly) SRReadyState readyState;
@property (nonatomic, readonly, retain) NSURL *url;
@property (nonatomic, readonly) CFHTTPMessageRef receivedHTTPHeaders;
@property (nonatomic, copy) NSArray *requestCookies;
@property (nonatomic, readonly, copy) NSString *protocol;
|
下面这些是SRWebSocket的一些方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
- (instancetype)initWithURLRequest:(NSURLRequest *)request;
- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols;
- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates;
- (instancetype)initWithURL:(NSURL *)url;
- (instancetype)initWithURL:(NSURL *)url protocols:(NSArray *)protocols;
- (instancetype)initWithURL:(NSURL *)url protocols:(NSArray *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates;
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
- (void)open;
- (void)close;
- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason;
#pragma mark Send
- (void)send:(id)message __attribute__((deprecated( "Please use `sendString:` or `sendData` instead." )));
- (void)sendString:(NSString *)string;
- (void)sendData:(NSData *)data;
- (void)sendPing:(NSData *)data;
@end
|
对应5种状态的代理方法
1
2
3
4
5
6
7
8
9
10
11
12
|
#pragma mark - SRWebSocketDelegate
@protocol SRWebSocketDelegate - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
@optional
- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload;
- (BOOL)webSocketShouldConvertTextFrameToString:(SRWebSocket *)webSocket;
@end
|
didReceiveMessage方法是必须实现的,用来接收消息的。
下面4个did方法分别对应着Open,Fail,Close,ReceivePong不同状态的代理方法
方法就上面这些了,我们实际来看看代码怎么写
先是初始化Websocket连接,注意此处ws://或者wss://连接有且最多只能有一个,这个是Websocket协议规定的
1
2
3
4
|
self.ws = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString
stringWithFormat:@ "%@://%@:%zd/ws" , serverProto, serverIP, serverPort]]]];
self.ws.delegate = delegate;
[self.ws open];
|
发送消息
接收消息以及其他3个代理方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message
{
NSDictionary *data = [NetworkUtils decodeData:message];
if (!data)
return ;
}
- (void)webSocketDidOpen:(SRWebSocket *)webSocket
{
[self.ws receivedPing];
}
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
{
[self failedConnection:NSLS(Disconnected)];
}
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error
{
[self failedConnection:NSLS(Disconnected)];
}
|
最后
以上就是我想分享的一些关于Websocket的心得,文中如果有错误的地方,欢迎大家指点!一般没有微信QQ那么大用户量的app,用Websocket应该都可以完成IM社交聊天的任务。当用户达到亿级别,应该还有很多需要优化,优化性能各种的吧。
最后,微信和QQ的实现方法也许并不是只用Websocket和Socket这么简单,也许是他们自己开发的一套能支持这么大用户,大数据的,各方面也都优化都最优的方法。如果有开发和微信和QQ的大神看到这篇文章,可以留言说说看你们用什么方式实现的,也可以和我们一起分享,我们一起学习!我先谢谢大神们的指点了!
1,Android 客户端使用需要配置网络权限;
2,需要写一个自己的client类来继承WebsocketClient;实现websocket的状态回调和新消息的解析动作;
3,需要监控自己的client的链接状态,维持长链接;
4,发送和接收
下面贴出部分相关代码;
网络权限的不用说了吧!
client类:
常用状态回调方法有4个;
自己可以在对应的函数里面做响应的处理,比如当链接发生错误时要重新去打开该链接,收到消息时即时的保存聊天记录和发送系统通知来提醒用户查看新消息等等;
- <pre name="code" class="html"><span style="font-size:18px;">public class TestClient extends WebSocketClient {
-
- public TestClient(URI serverURI) {
- super(serverURI);
- }
- /***
- * 链接关闭
- */
- @Override
- public void onClose(int arg0, String arg1, boolean arg2) {
-
- }
- /***
- * 链接发生错误
- */
- @Override
- public void onError(Exception arg0) {
-
- }
- /**
- * 新消息
- */
- @Override
- public void onMessage(String arg0) {
-
- }
- /***
- * 链接打开
- */
- @Override
- public void onOpen(ServerHandshake arg0) {
- // TODO Auto-generated method stub
-
- }
- }
- </span>
下面是我聊天部分代码,有离线消息/PC同步/多对多的聊天;
仅供参考;
- public class WebSocket extends WebSocketClient {
-
- public static final String LOGIN_RETURN_TYPE = "login";
-
- public static final String SEND_RETURN_TYPE = "send_result";
-
- public static final String RECEIVER_RETURN_TYPE = "msg";
-
- public static final String GET_SERVER_RETURN_TYPE = "server_info";
-
- public static final String CONTACTS_MAX_WEBID_TYPE = "max_id_return";
-
- public static final String USER_OFFLINE_MSG_TYPE = "offline";
-
- private Context mContext;
-
- private WebSocketParser mParser;
-
- public NotificationManager mNotificationManager;
-
- private Notification mNoti;
-
- private PendingIntent mIntent;
-
- public static final int NOTIFICATION_ID = 100;
-
- @SuppressWarnings("deprecation")
- public SGWebSocket(Context context, URI serverUri, Draft draft) {
- super(serverUri, draft);
- this.mContext = context;
-
- this.mParser = WebSocketParser.getInstance();
-
- this.mNotificationManager = (NotificationManager) this.mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
- this.mNoti = new Notification(R.drawable.system_info, "您有新消息!",
- System.currentTimeMillis());
- }
-
-
- @Override
- public void onClose(int arg0, String arg1, boolean arg2) {
-
- UserInfoUtil.saveSocket(mContext, false);
- mNotificationManager.cancelAll();
- Intent intent = new Intent(SocketConstant.ON_CLOSES);
- intent.putExtra(SocketConstant.ON_CLOSES, arg1.toString());
- mContext.sendBroadcast(intent);
- }
-
-
- @Override
- public void onError(Exception arg0) {
- Intent intent = new Intent(SGSocketConstant.ON_ERROR);
- intent.putExtra(SGSocketConstant.ON_ERROR, arg0.toString());
- mContext.sendBroadcast(intent);
- this.close();
- }
-
-
- public static final String MSG_BUYER_TYPE = "1";
-
- public static final String MSG_SERVCER_TYPE = "2";
-
-
-
-
-
- @Override
- public void onMessage(String content) {
-
- try {
- JSONObject object = new JSONObject(content);
- Log.i("json", "卖家--" + object.toString());
- String back_type = object.getString("back_type");
- String activity = getRunningActivityName();
- if (SEND_RETURN_TYPE.equals(back_type)) {
-
- MessageEntity entity = mParser.sendMessageParser(mContext,
- content);
- if ("true".equals(entity.getSend_state())) {
-
-
- boolean has = MessageDB.getInstance(mContext)
- .findMessageByMsgId(entity.get_id());
- if (has) {
-
- MessageDB.getInstance(mContext).update(entity.get_id(),
- true, entity.getReceiverTime(),
- entity.getWebId());
- } else {
-
- entity.setSend_state(SocketConstant.MSG_SEND_SUCCESS_STATE);
- MessageDB.getInstance(mContext).insert(entity,
- SocketConstant.MSG_TYPE_BUYER);
-
- pcSynAndroid(activity);
- }
-
- checkMsgWebId(entity.getContacts(), entity.getWebId());
- Log.i("miss", "发送返回或者PC同步--" + entity.getContacts() + "--"
- + entity.getWebId());
- } else if ("false".equals(entity.getSend_state())) {
- MessageDB.getInstance(mContext).update(entity.get_id(),
- false, entity.getReceiverTime(), entity.getWebId());
- Toast.makeText(mContext, entity.getErrorText(),
- Toast.LENGTH_SHORT).show();
- }
-
- } else if (LOGIN_RETURN_TYPE.equals(back_type)) {
- KApplication.session = object.getString("session_id");
- String str = object.getString("login_status");
- if ("true".equals(str)) {
- UserInfoUtil.saveSocket(mContext, true);
-
- String maxIdstring = SocketJsonUtil
- .getContactsCurrentWebId(UserInfoUtil
- .getUser(mContext)[0], "2", MessageDB
- .getInstance(mContext)
- .findAllContactsAndType());
-
- send(maxIdstring);
- Log.i("send", maxIdstring);
- } else if ("false".equals(str)) {
- UserInfoUtil.saveSocket(mContext, false);
- }
-
- } else if (RECEIVER_RETURN_TYPE.equals(back_type)) {
-
- MessageEntity entity = mParser.receiverMessagePrser(mContext,
- content);
-
- if (!MessageDB.getInstance(mContext).findMessageByMsgId(
- entity.get_id())) {
-
- if (MSG_BUYER_TYPE.equals(entity.getSenderType())) {
-
- messageHandle(entity, SocketConstant.MSG_TYPE_BUYER);
- } else if (MSG_SERVCER_TYPE.equals(entity.getSenderType())) {
-
- messageHandle(entity, SocketConstant.MSG_TYPE_SERVER);
- }
- Log.i("miss", "没有该条消息");
-
- checkMsgWebId(entity.getContacts(), entity.getWebId());
- }
- } else if (GET_SERVER_RETURN_TYPE.equals(back_type)) {
-
- ServerEntity entity = mParser.serverInfoParser(content);
- Intent intent = new Intent(SocketConstant.GET_SERVER_INFO);
- intent.putExtra("server_info", entity);
- mContext.sendBroadcast(intent);
- } else if (CONTACTS_MAX_WEBID_TYPE.equals(back_type)) {
-
- HashMap<String, String> map = mParser.contactsMaxWebId(content);
-
- saveContactsWebID(map);
-
- send(SocketJsonUtil.getOffLine(
- UserInfoUtil.getUser(mContext)[0], "2"));
- Log.i("send",
- SocketJsonUtil.getOffLine(
- UserInfoUtil.getUser(mContext)[0], "2"));
- } else if (USER_OFFLINE_MSG_TYPE.equals(back_type)) {
-
- HashMap<String, ArrayList<MessageEntity>> map = mParser
- .offLineMsg(mContext, content);
-
- saveOffLineMsg(map);
- }
- } catch (JSONException e) {
- this.close();
- }
- }
-
-
- @Override
- public void onOpen(ServerHandshake arg0) {
- Intent intent = new Intent(SGSocketConstant.ON_OPEN);
- mContext.sendBroadcast(intent);
- }
-
-
- private String getRunningActivityName() {
- ActivityManager activityManager = (ActivityManager) mContext
- .getSystemService(Context.ACTIVITY_SERVICE);
- String runningActivity = activityManager.getRunningTasks(1).get(0).topActivity
- .getClassName();
- return runningActivity;
- }
-
-
- @SuppressWarnings("deprecation")
- private void sendNotification(String contacts) {
- Intent intent = new Intent(mContext, MainActivity.class);
- mIntent = PendingIntent.getActivity(mContext, 100, intent, 0);
- mNoti.flags = Notification.FLAG_AUTO_CANCEL;
- mNoti.defaults = Notification.DEFAULT_VIBRATE;
- mNoti.setLatestEventInfo(mContext, "标题", "您有新消息!", mIntent);
- mNoti.contentView = new RemoteViews(mContext.getApplicationContext()
- .getPackageName(), R.layout.notification_item);
- mNoti.contentView.setTextViewText(R.id.noti_message, "收到来自" + contacts
- + "的新消息");
- mNotificationManager.notify(NOTIFICATION_ID, mNoti);
- }
-
-
- private void messageHandle(MessageEntity entity, String messageType) {
- String activity = getRunningActivityName();
-
- if ("com.ui.activity.ManageChartActivity".equals(activity)) {
-
- if (KApplication.crurentContacts.equals(entity.getContacts())) {
-
- entity.setSend_state(SocketConstant.MSG_SEND_SUCCESS_STATE);
- entity.setRead(SocketConstant.READ_STATE);
- MessageDB.getInstance(mContext).insert(entity, messageType);
- Intent intent = new Intent(SocketConstant.NEW_MESSAGE);
- intent.putExtra("newmsg", entity);
- mContext.sendBroadcast(intent);
-
- } else {
- entity.setSend_state(SocketConstant.MSG_SEND_SUCCESS_STATE);
- entity.setRead(SocketConstant.DEFAULT_READ_STATE);
- MessageDB.getInstance(mContext).insert(entity, messageType);
- if (KApplication.sp.getBoolean(RefreshUtils.noteFlag, false)) {
- sendNotification(entity.getContacts());
- }
- Intent intent = new Intent(
- SocketConstant.RECEIVER_NEW_MESSAGE);
- mContext.sendBroadcast(intent);
- }
-
- } else {
- entity.setSend_state(SocketConstant.MSG_SEND_SUCCESS_STATE);
- entity.setRead(SocketConstant.DEFAULT_READ_STATE);
- MessageDB.getInstance(mContext).insert(entity, messageType);
- Intent intent = new Intent();
- if ("com.ui.activity.ManageConversationActivity"
- .equals(activity)
- || "com.ui.activity.MainActivity"
- .equals(activity)) {
- intent.setAction(SocketConstant.RECEIVER_NEW_MESSAGE);
- } else {
- intent.setAction(SocketConstant.RECEIVER_NEW_MESSAGE_OTHER);
- }
- mContext.sendBroadcast(intent);
- if (KApplication.sp.getBoolean(RefreshUtils.noteFlag, false)) {
- sendNotification(entity.getContacts());
- }
- }
-
- }
-
-
- public void pcSynAndroid(String currentActivity) {
- if ("com.iflashseller.ui.activity.ManageChartActivity"
- .equals(currentActivity)) {
-
- Intent intent = new Intent(SocketConstant.CHART_ACTIVITY);
- mContext.sendBroadcast(intent);
- } else {
-
- Intent intent = new Intent(SocketConstant.GROUPS_ACTIVITY);
- mContext.sendBroadcast(intent);
- }
- }
-
-
- public void checkMsgWebId(String contacts, int webId) {
-
- if (KApplication.webIds.containsKey(contacts)) {
- Log.i("miss", "保存的--" + KApplication.webIds.get(contacts));
-
- int c = KApplication.webIds.get(contacts);
-
- if (webId > c && (webId - 1) != c) {
-
- for (int i = c + 1; i < webId; i++) {
-
- String miss = SocketJsonUtil.getMissMsg(
- UserInfoUtil.getUser(mContext)[0], "2", contacts,
- "1", i + "");
- this.send(miss);
- Log.i("miss", miss);
- }
-
- } else if (webId > c && (webId - 1) == c) {
- KApplication.webIds.put(contacts, webId);
- Log.i("miss", "修改的--" + contacts + "--" + webId);
- }
-
- } else {
- KApplication.webIds.put(contacts, webId);
- Log.i("miss", "新增--" + contacts + "--" + webId);
- }
- }
-
-
- public void saveContactsWebID(HashMap<String, String> map) {
- Iterator<Entry<String, String>> iter = map.entrySet().iterator();
- while (iter.hasNext()) {
- Entry<String, String> es = iter.next();
- String contacts = es.getKey();
- String maxWebID = es.getValue();
- KApplication.webIds.put(contacts, Integer.parseInt(maxWebID));
- }
- }
-
-
- public void saveOffLineMsg(HashMap<String, ArrayList<MessageEntity>> map) {
- Iterator<Entry<String, ArrayList<MessageEntity>>> iter = map.entrySet()
- .iterator();
- while (iter.hasNext()) {
- ArrayList<MessageEntity> msgs = iter.next().getValue();
- for (int i = 0; i < msgs.size(); i++) {
- threadSleep(100);
- MessageDB.getInstance(mContext).insert(msgs.get(i),
- SocketConstant.MSG_TYPE_BUYER);
- Log.i("write", "离线数据入库---" + msgs.get(i).toString());
- }
-
- if (msgs.size() >= 10) {
- send(SocketJsonUtil.getOffLine(
- UserInfoUtil.getUser(mContext)[0], "2"));
- Log.i("send",
- SocketJsonUtil.getOffLine(
- UserInfoUtil.getUser(mContext)[0], "2"));
- }
- }
-
- mContext.sendBroadcast(new Intent(
- SocketConstant.OFFLINE_MSG_RECEIVER_SUCCESS));
- }
-
- private void threadSleep(long time) {
- try {
- Thread.currentThread();
- Thread.sleep(time);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
至于数据库的一部分代码就不贴出了,无非是增删改查。
下面贴出部分监控链接状态的代码,以保证能即时的收到消息;
- public class LApplication extends Application {
-
- public static String TAG = LApplication.class.getSimpleName();
-
- private LPullReceiver mPullReceiver;
-
- public static boolean isLoging = false;
-
- private LPushManager mWebSocket;
-
-
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- mPullReceiver = new LPullReceiver();
-
- IntentFilter filter = new IntentFilter();
-
- filter.addAction(Intent.ACTION_TIME_TICK);
-
- filter.addAction(Intent.ACTION_BOOT_COMPLETED);
-
- filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-
- filter.addAction(Intent.ACTION_SCREEN_ON);
-
- registerReceiver(mPullReceiver, filter);
-
- mWebSocket = new LPushManager(getApplicationContext());
-
- LPushUser.saveSocket(getApplicationContext(), false);
-
- LPushUser.saveConnect(getApplicationContext(), false);
-
- long currentTime = System.currentTimeMillis();
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Date date = new Date(currentTime);
- String time = sdf.format(date);
-
- LPushUser.saveOpenTime(getApplicationContext(), time);
- }
-
-
- class LPullReceiver extends BroadcastReceiver {
- @SuppressLint("SimpleDateFormat")
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_TIME_TICK.equals(action)
- || ConnectivityManager.CONNECTIVITY_ACTION.equals(action)
- || Intent.ACTION_BOOT_COMPLETED.equals(action)
- || Intent.ACTION_SCREEN_ON.equals(action)) {
-
- if (LPushUser.GETLOG(getApplicationContext()))
- Log.i("lpush",
- "socket的链接状态----"
- + LPushUser
- .getSocket(getApplicationContext())
- + "是否正在链接--" + isLoging + "----" + action);
-
- if (!LPushUser.getSocket(getApplicationContext()) && !isLoging
- && LPushUser.getSocketEnable(getApplicationContext())
- && !"".equals(IP) && !"".equals(PORT)
- && !LPushUser.getConnectState(getApplicationContext())) {
-
-
-
- if (LNetworkUtil.netIsEnable(getApplicationContext())) {
- mWebSocket.secondMethod(IP, PORT);
-
-
- long currentTime = System.currentTimeMillis();
- SimpleDateFormat sdf = new SimpleDateFormat(
- "yyyy-MM-dd HH:mm:ss");
- Date date = new Date(currentTime);
- String time = sdf.format(date);
-
- LPushUser.saveOpenTime(getApplicationContext(), time);
- }
- } else {
-
-
- long currentTime = System.currentTimeMillis();
- SimpleDateFormat sdf = new SimpleDateFormat(
- "yyyy-MM-dd HH:mm:ss");
- Date date = new Date(currentTime);
- String time = sdf.format(date);
-
- long minTime = LStringManager.dateDifference(
- LPushUser.getOpenTime(getApplicationContext()),
- time);
- if (LPushUser.GETLOG(getApplicationContext())) {
- Log.i("lpush",
- "链接时长----现在时间:"
- + time
- + ";保存时间:"
- + LPushUser
- .getOpenTime(getApplicationContext())
- + ";时差" + minTime + "分钟");
- }
- if (minTime >= 5) {
-
-
-
-
- if (LPushUser.getConnectState(getApplicationContext())) {
- LPushUser.saveConnect(getApplicationContext(),
- false);
- }
- if (LNetworkUtil.netIsEnable(getApplicationContext())
- && LPushUser
- .getSocketEnable(getApplicationContext())) {
- mWebSocket.secondMethod(IP, PORT);
-
- LPushUser.saveOpenTime(getApplicationContext(),
- time);
- }
- }
- }
- }
- }
- }
-
-
- protected void setLPushEnable(boolean enable) {
- LPushUser.saveSocketEnable(getApplicationContext(), enable);
- }
-
-
-
- protected void setSocketIPInfo(String ip, String port) {
- this.IP = ip;
- this.PORT = port;
- }
-
-
-
-
- public void setUserInfo(int uid, String code) {
-
-
-
-
-
-
-
-
- LPushUser.saveUserID(getApplicationContext(), uid);
-
- LPushUser.saveUserCode(getApplicationContext(), code);
-
- mWebSocket.close();
- }
-
-
- public void openLogInfo(boolean flag) {
- LPushUser.SAVELOG(getApplicationContext(), flag);
- }
-
-
- private void reset() {
- LPushUser.saveConnect(getApplicationContext(), false);
- }
- }
UI界面显示部分就不贴出了,后面贴出Application类的目的就是监控各种手机系统的广播来嗅探自己的websocket链接的状态;用来维持它以保证能即时的收到消息;
Websocket实现即时通讯
标签:周期性 协议 cookies enable sync error: tools upd repr
原文地址:http://www.cnblogs.com/barrywxx/p/7412808.html