是这样的,目前要做一个这样的功能,需要有两个TCP客户端连接同时运行,就将他们命名为TCPA,TCPBTCPA 负责获取重要的参数信息,因为TCPB的有些通讯信息需要从TCPA里面获取,比如端口信息。TCPA还负责心跳信息,保持与服务器的连接。
TCPB 负责请求真正的数据。请问下,在IOS上应该如何做?我困恼了好几天了,希望各位大大帮助一下啊。因为是IOS新手,所以有些问题不是很懂。大大们最好提供一个demo程序给我,非常简单的即可。只要能够两个TCP客户端同时运行即可。demo可以发我邮箱[email protected]或者提供下载链接也可以。。小弟在这里,叩拜了。

解决方案 »

  1.   

    TCPA还负责心跳信息,保持与服务器的连接。这个是每个长连接都需要做的,而不是其中之一个连接
      

  2.   


    定义两个AsyncSocket对象就可以启动两个连接了。
    单个连接的例子:
    http://www.cnblogs.com/imlucky/archive/2011/10/18/2216829.html
      

  3.   


    你好,这个问题解决了,现在又出了一个问题,官方文档上说AsyncSocket只能在主线程中使用,因为要不停的收数据和线程休眠,就导致UI界面卡死。。请问下,可有解决办法。
      

  4.   

    “AsyncSocket只能在主线程中使用”你确定你没有看错?虽然我没有使用过该类库,但看名字就觉得不应该是只能在主线程中使用。自己重新启动一个线程,在这个线程里面收发数据。当接收到数据需要在UI显示的使用,使用
    performSelectorOnMainThread去显示。
      

  5.   


    有详细的例子吗?我每发送一次心跳包,然后sleep 10秒,这10秒内界面就卡死了。
      

  6.   


    先创建一个socket
     
    - (int)CSocket
    {
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        {
          perror("socket");
          exit(errno);    
        }
        return sockfd;
    }
    然后是链接
    //////////////////
    - (BOOL)ConnectToServer:(NSString*)addr port:(int)port
    {
        their_addr.sin_family = AF_INET;
        their_addr.sin_addr.s_addr = inet_addr([addr UTF8String]);
        their_addr.sin_port = htons(port);
        bzero(&(their_addr.sin_zero), 8);
        int conn = connect(sockfd, (struct sockaddr*)&their_addr, sizeof(struct sockaddr));
        NSLog(@"Connect error no is %d:",conn);
        return misConnect;
    }
     
    这样子的链接是阻塞的,这样子就比较不好,可以设置成非阻塞的方式来控制超时
        /***************************************************/
        //在connect之前,设成非阻塞模式
        int flags = fcntl(sockfd, F_GETFL,0);
        fcntl(sockfd,F_SETFL, flags | O_NONBLOCK);
        /***************************************************
        //这是另外一种设置成非阻塞的方式
         int flags;
         if((flags = fcntl(sockfd, F_GETFL)) < 0 )
         {
         perror("fcntl F_SETFL");
         }
         flags |= O_NONBLOCK;
         if(fcntl(sockfd, F_SETFL,flags) < 0)
         {
         perror("fcntl");
         }
        ****************************************************/
    设置connect后可以设置用select设置超时
    /***************************************************/
        //设置超时
        fd_set          fdwrite;
        struct timeval  tvSelect;
       
        FD_ZERO(&fdwrite);
        FD_SET(sockfd, &fdwrite);
        tvSelect.tv_sec = 2;
        tvSelect.tv_usec = 0;
        int retval = select(sockfd + 1,NULL, &fdwrite, NULL, &tvSelect);
        if(retval < 0)
        {
          if ( errno == EINTR )
          {
            NSLog(@"select error");
          }
          else
          {
            NSLog(@"error");
            close(sockfd);
          }
        }
        else if(retval == 0)
        {
          NSLog(@"select timeout........");
        }
        else if(retval > 0)
        {
          misConnect = YES;
        }
     
     
     
        /***************************************************/
        //在connect成功之后,设成阻塞模式
        flags = fcntl(sockfd, F_GETFL,0);
        flags &= ~ O_NONBLOCK;
        fcntl(sockfd,F_SETFL, flags);
     
        /***************************************************/
        //设置不被SIGPIPE信号中断,物理链路损坏时才不会导致程序直接被Terminate
        //在网络异常的时候如果程序收到SIGPIRE是会直接被退出的。
        struct sigaction sa;
        sa.sa_handler = SIG_IGN;
        sigaction( SIGPIPE, &sa, 0 );
        /***************************************************/
     
     
    然后就可以收发数据了
    send,write两种方法都可以,你需要自己维护一个队列,控制时间等等
        NSString *str = [SendCmdArray objectAtIndex:0];
        NSData *data = [str dataUsingEncoding:NSISOLatin1StringEncoding];
    //  ssize_t datalen = send(sockfd,[data bytes],[data length],0);
        ssize_t datalen = write(sockfd, [data bytes], [data length]);
        if(datalen == [data length])
        {
          NSLog(@"Send str:%@",str);
        }
     
     
    如何接收数据,read和recv都可以,这是方法,你需要自己维护一个队列,控制时间等等。
        char readBuffer[512] = {0};
        NSString* readString = nil;
        int br = 0; 
        while (br = read(sockfd, readBuffer, sizeof(readBuffer)) < sizeof(readBuffer))
    //  while((br = recv(sockfd, readBuffer, sizeof(readBuffer), 0)) < sizeof(readBuffer))
        {
          NSLog(@"Received CMD:%s",readBuffer);
          readString = [NSString stringWithUTF8String:readBuffer];
          memset(readBuffer,0,sizeof(readBuffer));
        }
        NSLog(@"br is %d,receive exit.",br);
     
     
    获取时间后就可以进行时间同步了,具体的时间同步协议要根据自己平台来设计
          time_t timep;
          struct tm *p;
          time(&timep);
          p = localtime(&timep);
          int wday = -1;//return num is (0,6),the weekday range is (1,7)
          if(p->tm_wday == 0)
            wday = 7;
          else
            wday = p->tm_wday;
          char data[256] = {0};
          sprintf(data,"0E4007%02x%02x%02x%02x%02x%02x%02x",(1900+p->tm_year)%100,(1+p->tm_mon),p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec,wday);
          NSString *msgtime = [NSString stringWithUTF8String:data];
     
    可以开一个线程来进行收发,处理相关的操作,想要多线程控制需要注意这个socket必须是全局可用的,因为新线程已经不在主循环了
    还有如果有界面更新也需要在主线程更新
     
    [NSThread detachNewThreadSelector:@selector(OnNewThread) toTarget:self withObject:nil];
     
    可以用timer做一个心跳包维持通讯
     
    timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(OnHeartBeatTimer:) userInfo:nil repeats:YES];
     
    结束的时候记得关掉定时器和socket
    [timer invalidate];
    close(sockfd);
      

  7.   


    你好,这个问题解决了,现在又出了一个问题,官方文档上说AsyncSocket只能在主线程中使用,因为要不停的收数据和线程休眠,就导致UI界面卡死。。请问下,可有解决办法。你的问题怎么解决的?是服务器的设置问题,还是用心跳包