在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);
}
returnsockfd;
}
然后是链接
//
-(BOOL)ConnectToServer:(NSString*)addrport:(int)port
{
their_addr.sin_family = AF_INET;
their_addr.sin_addr.s_addr = inet_addr([addrUTF8String]);
their_addr.sin_port = htons(port);
bzero(&(their_addr.sin_zero), 8);
int conn = connect(sockfd,(structsockaddr*)&their_addr, sizeof(struct sockaddr));
NSLog(@"Connect error no is%d:",conn);
returnmisConnect;
}
这样子的链接是阻塞的,这样子就比较不好,可以设置成非阻塞的方式来控制超时
//在connect之前,设成非阻塞模式
int flags = fcntl(sockfd,F_GETFL,0);
fcntl(sockfd,F_SETFL, flags | O_NONBLOCK);
设置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(@"selecterror");
}
else
{
NSLog(@"error");
close(sockfd);
}
}
else if(retval == 0)
{
NSLog(@"selecttimeout........");
}
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 sigactionsa;
sa.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &sa, 0 );
然后就可以收发数据了
send,write两种方法都可以,你需要自己维护一个队列,控制时间等等
NSString *str = [SendCmdArray objectAtIndex:0];
NSData *data = [strdataUsingEncoding:NSISOLatin1StringEncoding];
// ssize_t datalen =send(sockfd,[data bytes],[data length],0);
ssize_t datalen = write(sockfd, [data bytes], [datalength]);
if(datalen == [datalength])
{
NSLog(@"Sendstr:%@",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(@"ReceivedCMD:%s",readBuffer);
readString = [NSStringstringWithUTF8String:readBuffer];
memset(readBuffer,0,sizeof(readBuffer));
}
NSLog(@"br is %d,receiveexit.",br);
获取时间后就可以进行时间同步了,具体的时间同步协议要根据自己平台来设计
time_t timep;
struct tm*p;
time(&timep);
p = localtime(&timep);
int wday = -1;//returnnum 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,"0E4007xxxxxxx",(1900+p->tm_year)%100,(1+p->tm_mon),p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec,wday);
NSString *msgtime = [NSStringstringWithUTF8String:data];
可以开一个线程来进行收发,处理相关的操作,想要多线程控制需要注意这个socket必须是全局可用的,因为新线程已经不在主循环了
还有如果有界面更新也需要在主线程更新
[NSThreaddetachNewThreadSelector:@selector(OnNewThread)toTarget:selfwithObject:nil];
可以用timer做一个心跳包维持通讯
timer = [NSTimerscheduledTimerWithTimeInterval:2 target:self selector:@selector(OnHeartBeatTimer:) userInfo:nil repeats:YES];
结束的时候记得关掉定时器和socket
[timer invalidate];
close(sockfd);