用socket可以实现像QQ那样发送即时消息的功能。客户端和服务端需要建立长连接,在长连接的情况下,发送消息。客户端可以发送心跳包来检测长连接。
在iOS开发中使用socket,一般都是用第三方库AsyncSocket,不得不承认这个库确实很强大。下载地址CocoaAsyncSocket
。
特性
AsyncSocket类是支持TCP的。
AsyncUdpSocket是支持UDP的。
AsyncSocket是封装了CFSocket和CFSteam的TCP/IP socket网络库。它提供了异步操作,本地cocoa类的基于delegate的完整支持。主要有以下特性:
AsyncUdpSocket是UDP/IP socket网络库,包装自CFSocket。它的工作很像TCP版本,只不过是用于处理UDP的。它包括基于非阻塞队列的发送接收操作,完整的委托支持,基于runloop,自包含的类,以及支持IPV4和IPV6。
使用AsyncSocket的时候可以做一层封装,根据需求提供几个接口出来。比如:连接、断开连接、发送消息等等。还有接受消息,接受到的消息可以通过通知、代理、block等传出去。
下面简单介绍一下对AsyncSocket使用.一般来说,一个用户只需要建立一个socket长连接,所以可以用单例类方便使用。
定义单列类:LGSocketServe
LGSocketServe.h
// // LGSocketServe.h // AsyncSocketDemo //#import <Foundation/Foundation.h> #import "AsyncSocket.h"
@interface LGSocketServe : NSObject<AsyncSocketDelegate>
+ (LGSocketServe *)sharedSocketServe;
@end
// // LGSocketServe.m // AsyncSocketDemo //#import "LGSocketServe.h"
@implementation LGSocketServe
static LGSocketServe *socketServe = nil;
#pragma mark public static methods
+ (LGSocketServe *)sharedSocketServe { @synchronized(self) { if(socketServe == nil) { socketServe = [[[self class] alloc] init]; } } return socketServe; }
+(id)allocWithZone:(NSZone *)zone { @synchronized(self) { if (socketServe == nil) { socketServe = [super allocWithZone:zone]; return socketServe; } } return nil; }
@end
LGSocketServe.h
@property (nonatomic, strong) AsyncSocket *socket; // socket// socket连接 - (void)startConnectSocket; LGSocketServe.m
//自己设定 #define HOST @"192.168.0.1" #define PORT 8080
//设置连接超时 #define TIME_OUT 20
- (void)startConnectSocket { self.socket = [[AsyncSocket alloc] initWithDelegate:self]; [self.socket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; if ( ![self SocketOpen:HOST port:PORT] ) {
}
}
- (NSInteger)SocketOpen:(NSString*)addr port:(NSInteger)port {
if (![self.socket isConnected]) { NSError *error = nil; [self.socket connectToHost:addr onPort:port withTimeout:TIME_OUT error:&error]; }
return 0; }
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port { //这是异步返回的连接成功, NSLog(@"didConnectToHost"); }
LGSocketServe.h
@property (nonatomic, retain) NSTimer *heartTimer; // 心跳计时器 LGSocketServe.m- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port { //这是异步返回的连接成功, NSLog(@"didConnectToHost");
//通过定时器不断发送消息,来检测长连接 self.heartTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(checkLongConnectByServe) userInfo:nil repeats:YES]; [self.heartTimer fire]; }
// 心跳连接 -(void)checkLongConnectByServe{
// 向服务器发送固定可是的消息,来检测长连接 NSString *longConnect = @"connect is here"; NSData *data = [longConnect dataUsingEncoding:NSUTF8StringEncoding]; [self.socket writeData:data withTimeout:1 tag:1]; }
断开连接
1,用户手动断开连接
LGSocketServe.h
// 断开socket连接 -(void)cutOffSocket; LGSocketServe.m-(void)cutOffSocket { self.socket.userData = SocketOfflineByUser; [self.socket disconnect]; }
2,wifi断开,socket断开连接
LGSocketServe.m
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err {NSLog(@" willDisconnectWithError %ld err = %@",sock.userData,[err description]); if (err.code == 57) { self.socket.userData = SocketOfflineByWifiCut; }
}
重新连接
socket断开之后会回调:
LGSocketServe.m
- (void)onSocketDidDisconnect:(AsyncSocket *)sock {NSLog(@"7878 sorry the connect is failure %ld",sock.userData);
if (sock.userData == SocketOfflineByServer) { // 服务器掉线,重连 [self startConnectSocket]; } else if (sock.userData == SocketOfflineByUser) {
// 如果由用户断开,不进行重连 return; }else if (sock.userData == SocketOfflineByWifiCut) {
// wifi断开,不进行重连 return; }
}
发送消息
LGSocketServe.h
// 发送消息 - (void)sendMessage:(id)message; LGSocketServe.m//设置写入超时 -1 表示不会使用超时 #define WRITE_TIME_OUT -1
- (void)sendMessage:(id)message { //像服务器发送数据 NSData *cmdData = [message dataUsingEncoding:NSUTF8StringEncoding]; [self.socket writeData:cmdData withTimeout:WRITE_TIME_OUT tag:1]; }
//发送消息成功之后回调 - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag {
}
接受消息
LGSocketServe.m
//设置读取超时 -1 表示不会使用超时 #define READ_TIME_OUT -1#define MAX_BUFFER 1024
//发送消息成功之后回调 - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag { //读取消息 [self.socket readDataWithTimeout:-1 buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0]; }
//接受消息成功之后回调 - (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { //服务端返回消息数据量比较大时,可能分多次返回。所以在读取消息的时候,设置MAX_BUFFER表示每次最多读取多少,当data.length < MAX_BUFFER我们认为有可能是接受完一个完整的消息,然后才解析 if( data.length < MAX_BUFFER ) { //收到结果解析... NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil]; NSLog(@"%@",dic); //解析出来的消息,可以通过通知、代理、block等传出去
}
[self.socket readDataWithTimeout:READ_TIME_OUT buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];
出错处理
LGSocketServe.m
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err { NSData * unreadData = [sock unreadData]; // ** This gets the current buffer if(unreadData.length > 0) { [self onSocket:sock didReadData:unreadData withTag:0]; // ** Return as much data that could be collected } else {NSLog(@" willDisconnectWithError %ld err = %@",sock.userData,[err description]); if (err.code == 57) { self.socket.userData = SocketOfflineByWifiCut; } }
}
使用
导入#import “LGSocketServe.h”
LGSocketServe *socketServe = [LGSocketServe sharedSocketServe]; //socket连接前先断开连接以免之前socket连接没有断开导致闪退 [socketServe cutOffSocket]; socketServe.socket.userData = SocketOfflineByServer; [socketServe startConnectSocket];//发送消息 @"hello world"只是举个列子,具体根据服务端的消息格式 [socketServe sendMessage:@"hello world"];
现在我正在开发一个能够接收通知的应用程序,进展顺利,直到我需要向服务器发送应用程序上收到的通知的副本。 虽然我知道这种方法的缺点,但这是我处理收到的通知的唯一方法。 现在我可以通过这个方法处理应用程序在后台和前台收到的通知 。在此方法中,我调用NSURLConnection sendAsynchronousRequest将收到的通知数据发送到我的服务器。 但是,当应用程序被删除(从后台应用程序中删
本文向大家介绍深入浅出讲解:php的socket通信原理,包括了深入浅出讲解:php的socket通信原理的使用技巧和注意事项,需要的朋友参考一下 对TCP/IP、UDP、Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵。那么我想问: 1. 什么是TCP/IP、UDP? 2. Socket在哪里呢? 3. Socket是什么呢? 4. 你会使用它们吗? 什么
本文向大家介绍C#中Socket通信用法实例详解,包括了C#中Socket通信用法实例详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#中Socket通信用法。分享给大家供大家参考。具体如下: 一、UDP方式: 服务器端代码: 客户端代码: 二、TCP方式: 服务器端代码: 客户端代码: 希望本文所述对大家的C#程序设计有所帮助。
我知道类似的问题已经被问过很多次了。但在阅读了这些帖子之后,我仍然感到非常困惑,尤其是在iOS 10中引入了之后。 官方文档提到了我可以处理远程通知的3种方法: 实现以在应用程序位于前台时处理通知 当应用程序处于后台或未运行时,实现 但文档中也提到:在iOS和tvOS中,系统将通知有效负载传递给app委托的方法 所以 要在应用处于后台/非活动状态时处理远程通知,我应该将我的代码放在3中的应用程序委
本文向大家介绍Android中使用socket通信实现消息推送的方法详解,包括了Android中使用socket通信实现消息推送的方法详解的使用技巧和注意事项,需要的朋友参考一下 原理 最近用socket写了一个消息推送的demo,在这里和大家分享一下。 主要实现了:一台手机向另外一台手机发送消息,这两台手机可以随时自由发送文本消息进行通信,类似我们常用的QQ。 效果图: 原理:手机通过socke
本文向大家介绍C#使用Protocol Buffer(ProtoBuf)进行Unity中的Socket通信,包括了C#使用Protocol Buffer(ProtoBuf)进行Unity中的Socket通信的使用技巧和注意事项,需要的朋友参考一下 首先来说一下本文中例子所要实现的功能: 基于ProtoBuf序列化对象 使用Socket实现时时通信 数据包的编码和解码 下面来看具体的步骤: 一、Un