zoukankan      html  css  js  c++  java
  • 轻松搞定iPhone socket 编程 用代码说话(iphone开发入门 4)

    轻松搞定iPhone socket 编程 用代码说话(iphone开发入门 4)   

    本人blog
    http://blog.csdn.net/ArthurChenJS/archive/2010/11/29/6043289.aspx

    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);
  • 相关阅读:
    << 和>> 的计算公式
    死锁面试题(什么是死锁,产生死锁的原因及必要条件)
    SpringBoot的注解:@SpringBootApplication注解 vs @EnableAutoConfiguration+@ComponentScan+@Configuration
    SpringBoot入门-15(springboot配置freemarker使用YML)
    shiro 登录
    springMVC RedirectAttributes
    IDEA3.5最新版激活码
    求递归算法时间复杂度:递归树
    渐进复杂度
    PL/SQL注册码
  • 原文地址:https://www.cnblogs.com/ligun123/p/2408297.html
Copyright © 2011-2022 走看看