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);
總結
以上是生活随笔為你收集整理的iphone开发之轻松搞定原生socket 编程,阻塞与非阻塞,收发自如的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle从零开始04——SQL语句0
- 下一篇: 1.01 与 37.8