//监听socket和管道处理函数;服务器的消息会通过socket发送给客户端,被select函数监听到,客户端内部消息会通过管道发送过来,停止select的监听;
//线程大部分时间处于该select函数,直到超时,所以它绝大部分时间起到10秒间隔的定时器的作用。
-(void)socketPipeSelectWithRet : (long *)ret
processResult : (PROCESS_RESULT *)processResult
timeval : (struct timeval *)tv
nowTime : (long long *)nowTime
readFdSet : (fd_set *)read_fd_set
waitTimeInterval : (long *)waitTimeInterval
max_fd : (int *)max_fd
{
LogDebug(@"函数");
[self processRequestTimeOut];
//当不处于登录中或登录成功的状态都结束长连接线程
if(!((LOGIN_ORDER_STATE_SUCESS == [[Singleton sharedInstance] getLoginOrderStat]) || (LOGIN_ORDER_STATE_LONGINING == [[Singleton sharedInstance] getLoginOrderStat])))
{
[self endSocket];
*processResult = PROCESS_RESULT_ABORT;
return;
}
if(SOCKECT_CONNECT_TIMEOUT == self.socketConnectStat)
{
//发送上线命令超时,可能socket异常,需要重新建立socket
// close(server_sock_fd);
if(self.fd > 0)
{
setsockopt(self.fd, SOL_SOCKET, SO_NOSIGPIPE, SIG_IGN, sizeof(int));
close(self.fd);
self.fd = -1;
}
self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
*processResult = PROCESS_RESULT_SKIP;
return;
}
if(self.fd <= 0)
{
self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
*processResult = PROCESS_RESULT_SKIP;
return;
}
if(self.fdReadPipe <= 0)
{
self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
*processResult = PROCESS_RESULT_SKIP;
[self processSocketPipeClosed];
return;
}
self.fdWriteFlag = YES;
FD_ZERO(read_fd_set);
FD_SET(self.fd, read_fd_set);
FD_SET(self.fdReadPipe, read_fd_set);
self.bServiceActiveSend = NO;
_bSendingFlag = YES;
if(![self.messagesArray isKindOfClass:[NSMutableArray class]])
{
self.messagesArray = [NSMutableArray array];
}
if(![self.sendMessagesArray isKindOfClass:[NSMutableArray class]])
{
self.sendMessagesArray = [NSMutableArray array];
}
if(![self.processedSendMsgArray isKindOfClass:[NSMutableArray class]])
{
self.processedSendMsgArray = [NSMutableArray array];
}
if((SOCKECT_CONNECT_SUCESS != self.socketConnectStat))
{
*waitTimeInterval = CONNECT_WAIT_TIME;
}
else if(self.hitOnLineTime > 0)
{
*waitTimeInterval = CONNECT_WAIT_TIME;
}
else if((0 == self.messagesArray.count) && (0 == self.sendMessagesArray.count) && (0 == self.processedSendMsgArray.count))
{
*waitTimeInterval = SELECT_INTERVAL_TIME;
}
else
{
*waitTimeInterval = CONNECT_WAIT_TIME;
}
_bSendingFlag = NO;
(*tv).tv_sec = *waitTimeInterval;
(*tv).tv_usec = 0;
//防止管道fd或socket的fd变更,需要计算出最大的fd
*max_fd = self.fd;
if(*max_fd < self.fdReadPipe)
{
*max_fd = self.fdReadPipe;
}
if(![self judgeConnectAfterNewestOnlySocketThread])
{
//已经重新建立长连接线程,这个线程不是最新建立的线程,为了长连接线程唯一性,需要立刻结束该线程,防止出现两个长连接线程
LogDebug(@"关闭连接时间超过20秒的线程, Thread Sno: %@\n", [self getSocketThreadSno]);
*processResult = PROCESS_RESULT_ABORT;
return;
}
LogDebug(@"judgeConnectAfterNewestOnlySocketThread after");
int set = 1;
setsockopt(self.fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
int write = 1;
setsockopt(self.fdReadPipe, SOL_SOCKET, SO_NOSIGPIPE, (void *)&write, sizeof(int));
//整个socket大部分时间会阻塞这这里,起到定时器的作用,能大大减少耗电量,收到管道消息或服务器发过来订单消息,select会立刻响应
//有订单时心跳为10秒,无订单时为60秒,若上次心跳和本次心跳间有其它消息发送就不发心跳消息了
// @try {
*ret = select(*max_fd + 1, read_fd_set, NULL, NULL, tv);
LogDebug(@"errno:%d\n", errno);
// } @catch (NSException *exception) {
// FLDDLogInfo(@"exception:%@", exception);
// self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
// *processResult = PROCESS_RESULT_ABORT;
// [self processSocketPipeClosed];
// return;
// } @finally {
//
// }
// FLDDLogDebug(@"select after");
LogDebug(@"ret2= %ld\n", *ret);
if(self.fd <= 0)
{
self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
*processResult = PROCESS_RESULT_SKIP;
return;
}
if(self.fdReadPipe <= 0)
{
self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
*processResult = PROCESS_RESULT_SKIP;
[self processSocketPipeClosed];
return;
}
if(![self judgeConnectAfterNewestOnlySocketThread])
{
//已经重新建立长连接线程,这个线程不是最新建立的线程,为了长连接线程唯一性,需要立刻结束该线程,防止出现两个长连接线程
LogDebug(@"关闭连接时间超过20秒的线程, Thread Sno: %@\n", [self getSocketThreadSno]);
_connectTime = (long long)[[NSDate date] timeIntervalSince1970];
*processResult = PROCESS_RESULT_ABORT;
return;
}
*nowTime = (long long)[[NSDate date] timeIntervalSince1970];
if((NotReachable == [self getNetworkStatus]) || (ReachableUnknown == [self getNetworkStatus]) || (EhostUnreach == [self getNetworkStatus]))
{
// close(server_sock_fd);
if(self.fd > 0)
{
setsockopt(self.fd, SOL_SOCKET, SO_NOSIGPIPE, SIG_IGN, sizeof(int));
close(self.fd);
self.fd = -1;
}
self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
*processResult = PROCESS_RESULT_SKIP;
return;
}
[self processRequestTimeOut];
*processResult = PROCESS_RESULT_NORMAL;
_einProgressCount++;
return;
}
//监听socket处理函数;主要是为了判定是否网卡缓冲是否已经满了,若网卡缓冲区满了,那么就不能通过长连接发送消息,或者可能出现数据丢失。
//一般select都会立刻响应,当然要处理监听期间有服务器的发送过来的消息和户端内部消息会通过管道发送过来的消息,当socket或管道中有数据没有读和网卡缓冲没有满可以写,select会立刻响应。
-(void)processReadWriteSelectNormalResultWithRet : (long)ret
processResult : (PROCESS_RESULT *)processResult
readFdSet : (fd_set *)read_fd_set
recv_msg : (unsigned char *)recv_msg
frontHearTime : (long long *)frontHearTime
frontSendMidPoitTime : (long long *)frontSendMidPoitTime
frontUpdatelocationTime : (long long *)frontUpdatelocationTime
nowTime : (long long *)nowTime
closeFlg : (BOOL *)closeFlg
handleFlag : (BOOL *)handleFlag
{
if(self.fd <= 0)
{
self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
*processResult = PROCESS_RESULT_SKIP;
return;
}
if(self.fdReadPipe <= 0)
{
self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
*processResult = PROCESS_RESULT_SKIP;
[self processSocketPipeClosed];
return;
}
//先把消息接收过来,后面再处理,防止再处理消息时,连接异常。
if (FD_ISSET(self.fd, read_fd_set))
{
LogDebug(@"ret2= %ld\n", ret);
bzero(recv_msg, BUFFER_SIZE);
long byte_num = recv(self.fd,recv_msg,BUFFER_SIZE,0);
if (byte_num > 0) {
LogDebug(@"服务器:%s\n",recv_msg);
LogDebug(@"byte_num= %ld\n, recv = %s\n", byte_num, recv_msg);
// [self decodeMessageWithRecvMsg:recv_msg msgByteNum:byte_num];
[self decodeMessageWithRecvMsg:recv_msg msgByteNum:byte_num frontHearTime:frontHearTime frontSendMidPoitTime:frontSendMidPoitTime frontUpdatelocationTime:frontUpdatelocationTime];
*handleFlag = YES;
}
else{
//收到的消息长度为0说明是socket已经断开,需要重新建立socket
LogDebug(@"select 出错!\n");
//close(server_sock_fd);
if(self.fd > 0)
{
setsockopt(self.fd, SOL_SOCKET, SO_NOSIGPIPE, SIG_IGN, sizeof(int));
close(self.fd);
self.fd = -1;
}
self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
*processResult = PROCESS_RESULT_SKIP;
return;
}
}
*closeFlg = NO;
LogDebug(@"判断管道里是否有数据\n");
if (FD_ISSET(self.fdReadPipe, read_fd_set))
{
LogDebug(@"ret2= %ld\n", ret);
long nbytes;
unsigned char readBuffer[PIPE_MESSAGE_MAX_BUFFER_LEN] = {0};
nbytes = read(self.fdReadPipe, readBuffer, PIPE_MESSAGE_MAX_BUFFER_LEN);
if((nbytes < 0) && (errno == EINTR))
{
//Interrupted system call,进程在一个慢系统调用(slow system call)中阻塞
*processResult = PROCESS_RESULT_CONTINUE;
return;
}
else if (nbytes <= 0) {
LogDebug(@"no data.");
}
else
{
readBuffer[PIPE_MESSAGE_MAX_BUFFER_LEN - 1] = '\n';
NSString *str = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%s", readBuffer]];
LogDebug(@"data:%@", str);
NSRange range1=[str rangeOfString:@",cancel quit" options:NSBackwardsSearch];
NSRange range2=[str rangeOfString:@",quit" options:NSBackwardsSearch];
NSRange range22=[str rangeOfString:receiveLocation options:NSBackwardsSearch];
NSRange range3=[str rangeOfString:@",send" options:NSBackwardsSearch];
NSRange range4=[str rangeOfString:@",net change" options:NSBackwardsSearch];
if(range1.length > 0)
{
self.isCloseSocket = NO;
LogDebug(@"收到取消关闭socket管道消息:%@", str);
}
else if(range2.length > 0)
{
//收到下线指令,发送了下线消息,立刻结束长连接线程
*closeFlg = YES;
}
else if(range22.length > 0)
{
[self immediatelySendMidPointUpdatelocationWthFrontHeatTime:frontHearTime frontSendMidPoitTime:frontSendMidPoitTime frontUpdatelocationTime:frontUpdatelocationTime];
}
else if(range3.length > 0)
{
LogDebug(@"收到发送消息管道消息:%@", str);
}
else if(range4.length > 0)
{
LogDebug(@"收到发送消息管道消息:%@", str);
//close(server_sock_fd);
if(self.fd > 0)
{
setsockopt(self.fd, SOL_SOCKET, SO_NOSIGPIPE, SIG_IGN, sizeof(int));
close(self.fd);
self.fd = -1;
}
self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
*processResult = PROCESS_RESULT_SKIP;
return;
}
}
}
*nowTime = (long long)[[NSDate date] timeIntervalSince1970];
LogDebug(@"nowTime - frontHearTime : %lld", *nowTime - *frontHearTime);
if(_bServiceActiveSend)
{
//发送心跳消息,收到响应消息直接删除就可以,客户端不需要根据心跳判断socket断连,直接通过读取字节数为0直接判断socket断连
if([self socketHeart])
{
*frontHearTime = *nowTime;
_bServiceActiveSend = NO;
}
}
*processResult = PROCESS_RESULT_NORMAL;
return;
}
//通过长连接的监控管道发送char *格式的消息
-(BOOL)sendMessageBySocketMonitorPipeWithCharArr : (const char *)message
{
NSUInteger len = 0;
len = strlen(message);
if(0 == len)
{
return YES;
}
unsigned char input_msg[MESSAGE_MAX_LEN] = {0};
memcpy(input_msg, message, len);;
@try {
if(self.fdWritePipe <= 0)
{
//守护线程管道已经关闭
[self processSocketPipeClosed];
return NO;
}
setsockopt([SingleAsyncSocket sharedInstance].fdWritePipe, SOL_SOCKET, SO_NOSIGPIPE, SIG_IGN, sizeof(int));
long ret = write(self.fdWritePipe, input_msg, len);
if((ret < 0) && (errno == EINTR))
{
if(self.fdWritePipe <= 0)
{
//守护线程管道已经关闭
[self processSocketPipeClosed];
return NO;
}
setsockopt([SingleAsyncSocket sharedInstance].fdWritePipe, SOL_SOCKET, SO_NOSIGPIPE, SIG_IGN, sizeof(int));
//Interrupted system call,进程在一个慢系统调用(slow system call)中阻塞
long ret = write(self.fdWritePipe, input_msg, len);
if(ret != len)
{
[self processSocketPipeClosed];
return NO;
}
else
{
return YES;
}
}
else if(ret != len)
{
[self processSocketPipeClosed];
return NO;
}
else
{
return YES;
}
}
@catch (NSException *exception) {
FLDDLogInfo(@"exception:%@", exception);
[self processSocketPipeClosed];
return NO;
}
@finally