From: http://www.writecodes.com/develop/343.html
在iphone的平台下,要进行socket开发其实有很多种的方法,开源的库Asyncsocket,官方的CFSocket,还有BSD的socket。这里要做一个简单的socket普及,这里包含在socket的设置非阻塞喝超时的控制逻辑,心跳包和线程的启动时间同步的控制。 这里都是标准的linux的流程,先创建一个socket:
1
2
3
4
5
6
7
8
9
- ( int ) CSocket
{
if ( ( sockfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == - 1 )
{
perror ( "socket" ) ;
exit ( errno ) ;
}
return sockfd;
}
然后是链接:
1
2
3
4
5
6
7
8
9
10
- ( 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( & amp;( their_addr.sin_zero) , 8 ) ;
int conn = connect( sockfd, ( struct sockaddr* ) & amp;their_addr, sizeof ( struct sockaddr) ) ;
NSLog( @ "Connect error no is %d:" ,conn) ;
return misConnect;
}
这样子的链接是阻塞的,这样子就比较不好,可以设置成非阻塞的方式来控制超时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//在connect之前,设成非阻塞模式
int flags = fcntl( sockfd, F_GETFL,0 ) ;
fcntl( sockfd,F_SETFL, flags | O_NONBLOCK) ;
//这是另外一种设置成非阻塞的方式
int flags;
if ( ( flags = fcntl( sockfd, F_GETFL) ) & lt; 0 )
{
perror ( "fcntl F_SETFL" ) ;
}
flags |= O_NONBLOCK;
if ( fcntl( sockfd, F_SETFL,flags) & lt; 0 )
{
perror ( "fcntl" ) ;
}
设置connect后可以设置用select设置超时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//设置超时
fd_set fdwrite;
struct timeval tvSelect;
FD_ZERO( & amp;fdwrite) ;
FD_SET( sockfd, & amp;fdwrite) ;
tvSelect.tv_sec = 2 ;
tvSelect.tv_usec = 0 ;
int retval = select( sockfd + 1 ,NULL , & amp;fdwrite, NULL , & amp;tvSelect) ;
if ( retval & lt; 0 )
{
if ( errno == EINTR )
{
NSLog( @ "select error" ) ;
}
else
{
NSLog( @ "error" ) ;
close( sockfd) ;
}
}
else if ( retval == 0 )
{
NSLog( @ "select timeout........" ) ;
}
else if ( retval & gt; 0 )
{
misConnect = YES ;
}
/***************************************************/
//在connect成功之后,设成阻塞模式
flags = fcntl( sockfd, F_GETFL,0 ) ;
flags & amp;= ~ O_NONBLOCK;
fcntl( sockfd,F_SETFL, flags) ;
/***************************************************/
//设置不被SIGPIPE信号中断,物理链路损坏时才不会导致程序直接被Terminate
//在网络异常的时候如果程序收到SIGPIRE是会直接被退出的。
struct sigaction sa;
sa.sa_handler = SIG_IGN ;
sigaction( SIGPIPE, & amp;sa, 0 ) ;
/***************************************************/
然后就可以收发数据了,send,write两种方法都可以,你需要自己维护一个队列,控制时间等等
1
2
3
4
5
6
7
8
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都可以,这是方法,你需要自己维护一个队列,控制时间等等。
1
2
3
4
5
6
7
8
9
10
11
char readBuffer[ 512 ] = { 0 } ;
NSString * readString = nil ;
int br = 0 ;
while ( br = read( sockfd, readBuffer, sizeof ( readBuffer) ) & lt; 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) ;
获取时间后就可以进行时间同步了,具体的时间同步协议要根据自己平台来设计
1
2
3
4
5
6
7
8
9
10
11
12
time_t timep;
struct tm * p;
time ( & amp;timep) ;
p = localtime ( & amp;timep) ;
int wday = - 1 ;//return num is (0,6),the weekday range is (1,7)
if ( p-& gt;tm_wday == 0 )
wday = 7 ;
else
wday = p-& gt;tm_wday;
char data[ 256 ] = { 0 } ;
sprintf ( data,"0E4007%02x%02x%02x%02x%02x%02x%02x" ,( 1900 + p-& gt;tm_year) % 100,( 1 + p-& gt;tm_mon) ,p-& gt;tm_mday,p-& gt;tm_hour,p-& gt;tm_min,p-& gt;tm_sec,wday) ;
NSString * msgtime = [ NSString stringWithUTF8String: data] ;
可以开一个线程来进行收发,处理相关的操作,想要多线程控制需要注意这个socket必须是全局可用的,因为新线程已经不在主循环了,还有如果有界面更新也需要在主线程更新
1
[ NSThread detachNewThreadSelector: @selector ( OnNewThread) toTarget: self withObject: nil ] ;
可以用timer做一个心跳包维持通讯
1
timer = [ NSTimer scheduledTimerWithTimeInterval: 2 target: selfselector: @selector ( OnHeartBeatTimer: ) userInfo: nil repeats: YES ] ;
结束的时候记得关掉定时器和socket
1
2
[ timer invalidate] ;
close( sockfd) ;
本文出自 “ArthurChen ” 博客:http://arthurchen.blog.51cto.com/2483760/577911