现在的位置: 首页 > 综合 > 正文

iphone开发之轻松搞定原生socket 编程,阻塞与非阻塞,收发自如

2018年07月31日 ⁄ 综合 ⁄ 共 3848字 ⁄ 字号 评论关闭

 

转自:http://blog.csdn.net/arthurchenjs/article/details/6043289

 

 

iphone socket开发

 

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

这里要做一个简单的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);

     }

   }

   elseif(retval
==0)

   {

     NSLog(@"select timeout........");

   }

   elseif(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 );

   /***************************************************/

 

 

然后就可以收发数据了

sendwrite两种方法都可以,你需要自己维护一个队列,控制时间等等

   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);

   }

 

 

如何接收数据,readrecv都可以,这是方法,你需要自己维护一个队列,控制时间等等。

   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);

【上篇】
【下篇】

抱歉!评论已关闭.