123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- //
- // KSTargetWebSocketManager.m
- // KulexiuForStudent
- //
- // Created by 王智 on 2024/8/13.
- //
- #import "KSTargetWebSocketManager.h"
- #import <AFNetworkReachabilityManager.h>
- /*自定义打印 宏*/
- #ifdef DEBUG
- #define KSNSLog(format, ...) do { \
- fprintf(stderr, "<%s : %d> %s\n", \
- [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], \
- __LINE__, __func__); \
- (NSLog)((format), ##__VA_ARGS__); \
- fprintf(stderr, "-------\n"); \
- } while (0)
- #else
- #define KSNSLog( ...)
- #endif
- typedef NS_ENUM(NSUInteger, SocketDataType) {
- distributeOrder,
- cancelCall,
- orderLost,
- changeDeviceType,
- };
- @interface KSTargetWebSocketManager ()<SRWebSocketDelegate>
- {
- NSTimer * heartBeat;
- NSTimeInterval reConnectTime;
- SocketDataType type;
- }
- @property (nonatomic,strong) SRWebSocket *socket;
- @end
- @implementation KSTargetWebSocketManager
- - (instancetype)init {
- self = [super init];
- if (self) {
- }
- return self;
- }
- - (void)registerNetworkNotifications{
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkChangedNote:) name:AFNetworkingReachabilityDidChangeNotification object:nil];
- }
- - (void)networkChangedNote:(NSNotification *)note{
-
- AFNetworkReachabilityStatus status = [note.userInfo[AFNetworkingReachabilityNotificationStatusItem] integerValue];
- switch (status) {
- case AFNetworkReachabilityStatusUnknown:
- NSLog(@"网络类型:未知网络");
- break;
- case AFNetworkReachabilityStatusNotReachable:
- NSLog(@"网络类型:断网");
- break;
- case AFNetworkReachabilityStatusReachableViaWWAN:
- NSLog(@"网络类型:数据流量");
- [self SRWebSocketOpen];
- break;
- case AFNetworkReachabilityStatusReachableViaWiFi:
- NSLog(@"网络类型:WIFI");
- [self SRWebSocketOpen];
- break;
- }
- }
- -(void)SRWebSocketOpen {
- //如果是同一个url return
- if (self.socket) {
- if (self.socket.readyState == SR_OPEN) {
- [self handleConnectionStatus:YES];
- return;
- }
- else {
- self.socket = nil;
- }
- }
-
- /** /userId */
- NSString *connectedUrl = [NSString stringWithFormat:@"%@/%@", SOCKET_URL, UserDefault(UIDKey)];
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:connectedUrl]];
- request.allHTTPHeaderFields = @{@"Authorization":[NSString stringWithFormat:@"%@ %@", UserDefault(Token_type), UserDefault(TokenKey)]};
- self.socket = [[SRWebSocket alloc] initWithURLRequest:
- request];//这里填写你服务器的地址
- NSLog(@"请求的websocket地址:%@",self.socket.url.absoluteString);
- self.socket.delegate = self; //实现这个 SRWebSocketDelegate 协议
- [self.socket open]; //open 就是直接连接了
- }
- - (void)SRWebSocketClose {
- if (self.socket) {
- [self.socket close];
- self.socket = nil;
- //断开连接时销毁心跳
- [self destoryHeartBeat];
- }
- }
- #pragma mark - socket delegate
- - (void)webSocketDidOpen:(SRWebSocket *)webSocket {
-
- //每次正常连接的时候清零重连时间
- reConnectTime = 0;
-
- //开启心跳
- [self initHeartBeat];
- if (webSocket == self.socket) {
- NSLog(@"************************** socket 连接成功************************** ");
- [self handleConnectionStatus:YES];
- }
- }
- - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
- if (webSocket == self.socket) {
- NSLog(@"************************** socket 连接失败************************** ");
- _socket = nil;
- //连接失败就重连
- [self reConnect];
- }
- }
- - (void)handleConnectionStatus:(BOOL)isSuccess {
- if (self.connectionStatus) {
- self.connectionStatus(isSuccess);
- }
- }
- - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
-
- if (webSocket == self.socket) {
- NSLog(@"************************** socket连接断开************************** ");
- NSLog(@"被关闭连接,code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);
- [self SRWebSocketClose];
- [self handleConnectionStatus:NO];
- }
- }
- /*该函数是接收服务器发送的pong消息,其中最后一个是接受pong消息的,
- 在这里就要提一下心跳包,一般情况下建立长连接都会建立一个心跳包,
- 用于每隔一段时间通知一次服务端,客户端还是在线,这个心跳包其实就是一个ping消息,
- 我的理解就是建立一个定时器,每隔十秒或者十五秒向服务端发送一个ping消息,这个消息可是是空的
- */
- -(void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload{
- NSString *reply = [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding];
- NSLog(@"reply===%@",reply);
- }
- #pragma mark - 收到的回调
- - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
-
- if (webSocket == self.socket) {
- NSLog(@"************************** socket收到数据了************************** ");
- NSLog(@"message:%@",message);
- if(!message){
- return;
- }
- [self handleReceivedMessage:message];
- }
- }
- - (void)handleReceivedMessage:(id)message {
-
- if(self.didReceiveMessage){
- self.didReceiveMessage(message);
- }
- }
- //重连机制
- - (void)reConnect
- {
-
- [self SRWebSocketClose];
- //超过一分钟就不再重连 所以只会重连5次 2^5 = 64
- NSLog(@"reConnectTime-----%.0f",reConnectTime);
- if (reConnectTime > 60) {
- //您的网络状况不是很好,请检查网络后重试
- [self handleConnectionStatus:NO];
- return;
- }
-
-
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- self.socket = nil;
- [self SRWebSocketOpen];
- NSLog(@"重连");
- });
-
- //重连时间2的指数级增长
- if (reConnectTime == 0) {
- reConnectTime = 2;
- }else{
- reConnectTime *= 2;
- }
-
- }
- //初始化心跳
- - (void)initHeartBeat
- {
- dispatch_main_async_safe(^{
- [self destoryHeartBeat];
-
- self->heartBeat = [NSTimer timerWithTimeInterval:30 target:self selector:@selector(ping) userInfo:nil repeats:YES];
- //和服务端约定好发送什么作为心跳标识,尽可能的减小心跳包大小
- [[NSRunLoop currentRunLoop]addTimer:self->heartBeat forMode:NSRunLoopCommonModes];
- })
- }
- //取消心跳
- - (void)destoryHeartBeat
- {
- dispatch_main_async_safe(^{
- if (self->heartBeat) {
- if ([self->heartBeat respondsToSelector:@selector(isValid)]){
- if ([self->heartBeat isValid]){
- [self->heartBeat invalidate];
- self->heartBeat = nil;
- }
- }
- }
- })
- }
- //pingPong
- - (void)ping{
- if (self.socket.readyState == SR_OPEN) {
- [self.socket sendPing:nil error:nil];
- }
- }
- - (void)sendData:(id)parmData {
-
- dispatch_queue_t queue = dispatch_queue_create("ks_websocket_queue", NULL);
- dispatch_async(queue, ^{
- if (self.socket != nil) {
- // 只有 SR_OPEN 开启状态才能调 send 方法啊,不然要崩
- if (self.socket.readyState == SR_OPEN) {
- // 发送数据
- if ([parmData isKindOfClass:[NSString class]]) {
- [self.socket sendString:parmData error:nil];
- }
- else if ([parmData isKindOfClass:[NSData class]]) {
- [self.socket sendData:parmData error:nil];
- }
- }
- else {
- [self SRWebSocketClose];
- [self handleConnectionStatus:NO];
- }
- /*else if (weakSelf.socket.readyState == SR_CONNECTING) {
- [weakSelf reConnect];
- } else if (weakSelf.socket.readyState == SR_CLOSING || weakSelf.socket.readyState == SR_CLOSED) {
- // websocket 断开了,调用 reConnect 方法重连
- NSLog(@"重连");
- [weakSelf reConnect];
- }*/
- } else {
- // 这里要看你的具体业务需求;不过一般情况下,调用发送数据还是希望能把数据发送出去,所以可以再次打开链接;不用担心这里会有多个socketopen;因为如果当前有socket存在,会停止创建哒
- [self SRWebSocketOpen];
- [self handleConnectionStatus:NO];
- }
- });
- }
- -(SRReadyState)socketReadyState{
- return self.socket.readyState;
- }
- -(void)dealloc{
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- NSLog(@"SocketRocketUtility dealloced");
- }
- @end
|