ios开发之iOS Socket 开发.docx
《ios开发之iOS Socket 开发.docx》由会员分享,可在线阅读,更多相关《ios开发之iOS Socket 开发.docx(16页珍藏版)》请在冰豆网上搜索。
ios开发之iOSSocket开发
ios开发之iOSSocket开发
这个类使用了Singleton,因此永远只有一个实例。
没有实例时会自动生成实例,可以在程序中的任何位置调用它。
一般来说,只要跟服务器建立一次连接即可,产生一对stream,分别是outStream和inStream,所有的数据都通过它们不断地发送和接收。
stream的end意味着连接中断,如果还需要访问服务器的话,得重新连接stream。
(也就是重新实例化一下我这个类)
每次发送和接受的数据包大小需要自己控制,而不是等stream来告诉你这个数据包有多大,因为stream不会告诉你……
控制方法之一:
通过添加一个特殊的后缀来判断,比如“”,每次读到这个组合就认为数据读完。
但是问题很明显,这个只能用于string。
控制方法之二:
通过添加一个4字节的前缀来判断长度。
这4个byte的byte[]数组,是当前数据包的长度信息,根据这个信息来读取一定长度的数据。
每次数据收完后,我用了一个取巧的方法来把数据返还给调用stream的函数……这个部分需要改进。
SynthesizeSingleton.h,实现singleton的类
1.//
2.// SynthesizeSingleton.h
3.// CocoaWithLove
4.//
5.// CreatedbyMattGallagheron20/10/08.
6.// Copyright2009MattGallagher.Allrightsreserved.
7.//
8.// Permissionisgiventousethissourcecodefilewithoutchargeinany
9.// project,commercialorotherwise,entirelyatyourrisk,withthecondition
10.// thatanyredistribution(inpartorwhole)ofsourcecodemustretain
11.// thiscopyrightandpermissionnotice.Attributionincompiledprojectsis
12.// appreciatedbutnotrequired.
13.//
14.
15.#defineSYNTHESIZE_SINGLETON_FOR_CLASS(classname)\
16.\
17.staticclassname*shared##classname=nil;\
18.\
19.+(classname*)shared##classname\
20.{\
21. @synchronized(self)\
22. {\
23. if(shared##classname==nil)\
24. {\
25. shared##classname=[[selfalloc]init];\
26. }\
27. }\
28. \
29. returnshared##classname;\
30.}\
31.\
32.+(id)allocWithZone:
(NSZone*)zone\
33.{\
34. @synchronized(self)\
35. {\
36. if(shared##classname==nil)\
37. {\
38. shared##classname=[superallocWithZone:
zone];\
39. returnshared##classname;\
40. }\
41. }\
42. \
43. returnnil;\
44.}\
45.\
46.-(id)copyWithZone:
(NSZone*)zone\
47.{\
48. returnself;\
49.}\
50.\
51.-(id)retain\
52.{\
53. returnself;\
54.}\
55.\
56.-(NSUInteger)retainCount\
57.{\
58. returnNSUIntegerMax;\
59.}\
60.\
61.-(void)release\
62.{\
63.}\
64.\
65.-(id)autorelease\
66.{\
67. returnself;\
68.}
复制代码
Stream.h
1.#import
2.#import
3.#import
4.#import
5.#import
6.
7.@interfaceStream:
NSObject{
8. NSInputStream *inStream;
9. NSOutputStream *outStream;
10. NSMutableData *dataBuffer;
11.
12. BOOL _hasEstablished;
13. id _currentObject;
14. int _numCondition;
15.
16. BOOL _isFirstFourBytes;
17. uint remainingToRead;
18.}
19.
20.+(Stream*)sharedStream;
21.-(void)requestData:
(NSString*)requestStringwhoRequest:
(id)currentObjectcondition:
(int)numCondition;
22.-(void)manageData:
(NSData*)receivedData;
23.@end
Stream.m
1.#import"Stream.h"
2.#import"SynthesizeSingleton.h"
3.
4.@implementationStream
5.
6.SYNTHESIZE_SINGLETON_FOR_CLASS(Stream);
7.
8.-(void)startClient
9.{
10. _hasEstablished=NO;
11. CFReadStreamRef readStream=NULL;
12. CFWriteStreamRef writeStream=NULL;
13. NSString *server=/*你的服务器地址,比如我公司服务器地址[url][/url]*/;
14. //这里没有用NSStream的getStreamsToHost,是因为真机编译时有黄色提示说不存在这个函数。
15. //虽然真机能用,但我担心上传到APPStore时会被reject,所以就用了更底层的CFStreamCreatePairWithSocketToHost。
16. //其实一点都不难,一样用的~
17. CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
18. (CFStringRef)server,
19. 1234,//服务器接收数据的端口
20. &readStream,
21. &writeStream);
22.
23.
24. if(readStream&&writeStream)
25. {
26. inStream=(NSInputStream*)readStream;
27. outStream=(NSOutputStream*)writeStream;
28. }
29. else
30. {
31. //ErrorControl
32. }
33.}
34.
35.-(void)closeStreams{
36. [[PromptViewsharedPromptView]dismissPromptView];
37. [inStreamclose];
38. [outStreamclose];
39. [inStreamremoveFromRunLoop:
[NSRunLoopcurrentRunLoop]forMode:
NSDefaultRunLoopMode];
40. [outStreamremoveFromRunLoop:
[NSRunLoopcurrentRunLoop]forMode:
NSDefaultRunLoopMode];
41. [inStreamsetDelegate:
nil];
42. [outStreamsetDelegate:
nil];
43. [inStreamrelease];
44. [outStreamrelease];
45. inStream=nil;
46. outStream=nil;
47.}
48.
49.-(void)openStreams{
50. [inStreamretain];
51. [outStreamretain];
52. [inStreamsetProperty:
NSStreamSocketSecurityLevelSSLv3forKey:
NSStreamSocketSecurityLevelKey];
53. [outStreamsetProperty:
NSStreamSocketSecurityLevelSSLv3forKey:
NSStreamSocketSecurityLevelKey];
54. //不需要SSL的话,下面这行可以去掉。
55. CFWriteStreamSetProperty((CFWriteStreamRef)outStream,kCFStreamPropertySSLSettings,[NSMutableDictionarydictionaryWithObjectsAndKeys:
(id)kCFBooleanFalse,kCFStreamSSLValidatesCertificateChain,kCFBooleanFalse,kCFStreamSSLIsServer,nil]);
56. [inStreamsetDelegate:
self];
57. [outStreamsetDelegate:
self];
58. [inStreamscheduleInRunLoop:
[NSRunLoopcurrentRunLoop]forMode:
NSDefaultRunLoopMode];
59. [outStreamscheduleInRunLoop:
[NSRunLoopcurrentRunLoop]forMode:
NSDefaultRunLoopMode];
60. [inStreamopen];
61. [outStreamopen];
62.}
63.
64.-(void)stream:
(NSStream*)aStreamhandleEvent:
(NSStreamEvent)eventCode
65.{
66. switch(eventCode){
67. caseNSStreamEventHasBytesAvailable:
68. {
69. if(_isFirstFourBytes)//读取前4个字节,算出数据包大小
70. {
71. uint8_tbufferLen[4];
72. if([inStreamread:
bufferLenmaxLength:
4]==4)
73. {
74. remainingToRead=((bufferLen[0]<<24)&0xff000000)+((bufferLen[1]<<16)&0xff0000)+((bufferLen[2]<<8)&0xff00)+(bufferLen[3]&0xff);
75. _isFirstFourBytes=NO;
76. }
77. else
78. {
79. [selfcloseStreams];
80. //ErrorControl
81. }
82. }
83. else//根据数据包大小读取数据
84. {
85. intactuallyRead;
86. uint8_tbuffer[32768];//32KB的缓冲区,缓冲区太小的话会明显影响真机上的通信速度
87. if(!
dataBuffer){
88. dataBuffer=[[NSMutableDataalloc]init];
89. }
90.
91. actuallyRead=[inStreamread:
buffermaxLength:
sizeof(buffer)];
92. if(actuallyRead==-1){
93. [selfcloseStreams];
94. //ErrorControl
95. }elseif(actuallyRead==0){
96. //Dosomethingifyouwant
97. }else{
98. [dataBufferappendBytes:
bufferlength:
actuallyRead];
99. remainingToRead-=actuallyRead;
100. }
101.
102. if(remainingToRead==0)
103. {
104. _isFirstFourBytes=YES;
105. [selfmanageData:
dataBuffer];//数据接收完毕,把数据送回调用sream的函数
106. [dataBufferrelease];
107. dataBuffer=nil;
108. }
109. }
110. break;
111. }
112. caseNSStreamEventEndEncountered:
//连接断开或结束
113. {
114. [selfcloseStreams];
115. break;
116. }
117. caseNSStreamEventErrorOccurred:
//无法连接或断开连接
118. {
119. if([[aStreamstreamError]code])//确定code不是0……有时候正常使用时会跳出code为0的错误,但其实一点问题都没有,可以继续使用,很奇怪……
120. {
121. [selfcloseStreams];
122. break;
123. }
124. }
125. caseNSStreamEventOpenCompleted:
126. {
127. _hasEstablished=YES;
128. break;
129. }
130. caseNSStreamEventHasSpaceAvailable:
131. {
132. break;
133. }
134. caseNSStreamEventNone:
135. default:
136. break;
137. }
138.}
139.
140.//判断是否能连接到服务器。
这个函数用来判断网络是否连通还好,要真的判断服务器上对应的端口是否可以连接,不是很好用来着……
141.-(BOOL)isServerAvailable{
142. NSString*addressString=/*你的服务器地址,比如我公司地址[url][/url]*/;
143. if(!
addressString){
144. returnNO;
145. }
146.
147. SCNetworkReachabilityRefdefaultRouteReachability=SCNetworkReachabilityCreateWithName(kCFAllocatorDefault,[addressStringUTF8String]);
148. SCNetworkReachabilityFlagsflags;
149.
150. BOOLdidRetrieveFlags=SCNetworkReachabilityGetFlags(defaultRouteReachability,&flags);
151. CFRelease(defaultRouteReachability);
152.
153. if(!
didRetrieveFlags)
154. {
155. returnNO;
156. }
157.
158. BOOLisReachable=flags&kSCNetworkFlagsReachable;
159. BOOLneedsConnection=flags&kSCNetworkFlagsConnectionRequired;
160. return(isReachable&&!
needsConnection)?
YES:
NO;
161.}
162.
163.-(void)requestData:
(NSString*)requestStringwhoRequest:
(id)currentObjectcondition:
(int)numCondition
164.{
165. if(!
[selfisServerAvailable])//如果无法连通到服务器
166. {
167. //ErrorControl
168. }
169. else
170. {
171. if(inStream==nil||outStream==nil)
172. {
173. [[StreamsharedStream]startClient];
174. [[StreamsharedStream]openStreams];
175. _isFirstFourBytes=YES;
176. }
177.
178. if(inStream!
=nil&&outStream!
=nil)
179. {
180. _currentObject=curr