zoukankan      html  css  js  c++  java
  • iphone开发之轻松搞定原生socket 编程,阻塞与非阻塞,收发自如

    iphone socket 开发

     

    在iphone的平台下,要进行socket开发其实有很多种的方法,开源的库Asyncsocket,官方的CFSocket,还有BSD的socket。

    这里要做一个简单的socket普及,这里包含在socket的设置非阻塞喝超时的控制逻辑,心跳包和线程的启动时间同步的控制。

     

    这里都是标准的linux的流程

    先创建一个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);

  • 相关阅读:
    120-136. 只出现一次的数字
    119-217. 存在重复元素
    118-103. 二叉树的锯齿形层序遍历
    117.力扣-两数相加问题
    116.python处理xmind文件
    115.python获取服务器信息
    日期转换类 DateConverter.java
    数据库连接工具类——包含取得连接和关闭资源 ConnUtil.java
    数据库连接工具类 数据库连接工具类——仅仅获得连接对象 ConnDB.java
    APP手机端加载不到资源服务器后台解决参考
  • 原文地址:https://www.cnblogs.com/zhwl/p/2877761.html
Copyright © 2011-2022 走看看