使用NSStream来实现Socket

swift-iOS基于NSStream实现的Socket长连接小封装 iOS基于NSStream实现的Socket长连接小封装 立即下载
这个类使用了Singleton,因此永远只有一个实例。没有实例时会自动生成实例,可以在程序中的任何位置调用它。
一般来说,只要跟服务器建立一次连接即可,产生一对stream,分别是outStream和inStream,所有的数据都通过它们不断地发送和接收。
stream的end意味着连接中断,如果还需要访问服务器的话,得重新连接stream。(也就是重新实例化一下我这个类)
每次发送和接受的数据包大小需要自己控制,而不是等stream来告诉你这个数据包有多大,因为stream不会告诉你……
控制方法之一:通过添加一个特殊的后缀来判断,比如“<EOF>”,每次读到这个组合就认为数据读完。但是问题很明显,这个只能用于string。
控制方法之二:通过添加一个4字节的前缀来判断长度。这4个byte的byte[]数组,是当前数据包的长度信息,根据这个信息来读取一定长度的数据。
每次数据收完后,我用了一个取巧的方法来把数据返还给调用stream的函数……这个部分需要改进。

代码
SynthesizeSingleton.h ,实现singleton的类
?
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//
//  SynthesizeSingleton.h
//  CocoaWithLove
//
//  Created by Matt Gallagher on 20/10/08.
//  Copyright 2009 Matt Gallagher. All rights reserved.
//
//  Permission is given to use this source code file without charge in any
//  project, commercial or otherwise, entirely at your risk, with the condition
//  that any redistribution (in part or whole) of source code must retain
//  this copyright and permission notice. Attribution in compiled projects is
//  appreciated but not required.
//
  
#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
  \
static classname *shared##classname = nil ; \
  \
+ (classname *)shared##classname \
{ \
     @synchronized ( self ) \
     { \
         if (shared##classname == nil ) \
         { \
             shared##classname = [[ self alloc] init]; \
         } \
     } \
      \
     return shared##classname; \
} \
  \
+ ( id )allocWithZone:( NSZone *)zone \
{ \
     @synchronized ( self ) \
     { \
         if (shared##classname == nil ) \
         { \
             shared##classname = [ super allocWithZone:zone]; \
             return shared##classname; \
         } \
     } \
      \
     return nil ; \
} \
  \
- ( id )copyWithZone:( NSZone *)zone \
{ \
     return self ; \
} \
  \
- ( id )retain \
{ \
     return self ; \
} \
  \
- ( NSUInteger )retainCount \
{ \
     return NSUIntegerMax ; \
} \
  \
- ( void )release \
{ \
} \
  \
- ( id )autorelease \
{ \
     return self ; \
}


Stream.h
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#import <foundation foundation.h=""> 
#import <cfnetwork cfnetwork.h="">
#import <systemconfiguration systemconfiguration.h="">
#import <netinet in.h="">
#import <arpa inet.h="">
 
@interface Stream : NSObject {
     NSInputStream    *inStream;
     NSOutputStream    *outStream;
     NSMutableData    *dataBuffer;
     
     BOOL            _hasEstablished;
     id                _currentObject;
     int                _numCondition;
     
     BOOL            _isFirstFourBytes;
     uint            remainingToRead;
}
 
+ (Stream *)sharedStream;
-( void )requestData:( NSString *)requestString whoRequest:( id )currentObject condition:( int )numCondition;
-( void )manageData:( NSData *)receivedData;
@end
</arpa></netinet></systemconfiguration></cfnetwork></foundation>


Stream.m
?
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#import "Stream.h"
#import "SynthesizeSingleton.h"
 
@implementation Stream
 
SYNTHESIZE_SINGLETON_FOR_CLASS(Stream);
 
-( void )startClient
{
     _hasEstablished = NO ;
     CFReadStreamRef        readStream = NULL ;
     CFWriteStreamRef    writeStream = NULL ;
     NSString            *server = /*你的服务器地址,比如我公司服务器地址[url]www.javista.com[/url]*/ ;
     //这里没有用NSStream的getStreamsToHost,是因为真机编译时有黄色提示说不存在这个函数。
     //虽然真机能用,但我担心上传到APP Store时会被reject,所以就用了更底层的CFStreamCreatePairWithSocketToHost。
     //其实一点都不难,一样用的~
     CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
                                        (CFStringRef)server,
                                        1234, //服务器接收数据的端口
                                        &readStream,
                                        &writeStream);
     
     
     if (readStream && writeStream)
     {
         inStream = ( NSInputStream *)readStream;
         outStream = ( NSOutputStream *)writeStream;
     }
     else
     {
         //Error Control
     }
}
 
-( void )closeStreams{
     [[PromptView sharedPromptView] dismissPromptView];
     [inStream close];
     [outStream close];
     [inStream removeFromRunLoop:[ NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode ];
     [outStream removeFromRunLoop:[ NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode ];
     [inStream setDelegate: nil ];
     [outStream setDelegate: nil ];
     [inStream release];
     [outStream release];
     inStream = nil ;
     outStream = nil ;
}
 
-( void )openStreams{
     [inStream retain];
     [outStream retain];
     [inStream setProperty: NSStreamSocketSecurityLevelSSLv3 forKey: NSStreamSocketSecurityLevelKey ];
     [outStream setProperty: NSStreamSocketSecurityLevelSSLv3 forKey: NSStreamSocketSecurityLevelKey ];
     //不需要SSL的话,下面这行可以去掉。
     CFWriteStreamSetProperty((CFWriteStreamRef)outStream, kCFStreamPropertySSLSettings, [ NSMutableDictionary dictionaryWithObjectsAndKeys:( id )kCFBooleanFalse,kCFStreamSSLValidatesCertificateChain,kCFBooleanFalse,kCFStreamSSLIsServer, nil ]);
     [inStream setDelegate: self ];
     [outStream setDelegate: self ];
     [inStream scheduleInRunLoop:[ NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode ];
     [outStream scheduleInRunLoop:[ NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode ];
     [inStream open];
     [outStream open];
}
 
- ( void )stream:( NSStream *)aStream handleEvent:( NSStreamEvent )eventCode
{
     switch (eventCode) {
         case NSStreamEventHasBytesAvailable :
         {
             if (_isFirstFourBytes) //读取前4个字节,算出数据包大小
             {
                 uint8_t bufferLen[4];
                 if ([inStream read:bufferLen maxLength:4] == 4)
                 {
                     remainingToRead = ((bufferLen[0]<<24)&0xff000000)+((bufferLen[1]<<16)&0xff0000)+((bufferLen[2]<<8)&0xff00)+(bufferLen[3] & 0xff);
                     _isFirstFourBytes = NO ;
                 }
                 else
                 {
                     [ self closeStreams];
                     //Error Control
                 }
             }
             else //根据数据包大小读取数据
             {
                 int actuallyRead;
                 uint8_t buffer[32768]; //32KB的缓冲区,缓冲区太小的话会明显影响真机上的通信速度
                 if (!dataBuffer) {
                     dataBuffer = [[ NSMutableData alloc] init];
                 }
                 
                 actuallyRead = [inStream read:buffer maxLength: sizeof (buffer)];
                 if (actuallyRead == -1){
                     [ self closeStreams];
                     //Error Control
                 } else if (actuallyRead == 0){
                     //Do something if you want
                 } else {
                     [dataBuffer appendBytes:buffer length:actuallyRead];
                     remainingToRead -= actuallyRead;
                 }
                 
                 if (remainingToRead == 0)
                 {
                     _isFirstFourBytes = YES ;
                     [ self manageData:dataBuffer]; //数据接收完毕,把数据送回调用sream的函数
                     [dataBuffer release];
                     dataBuffer = nil ;
                 }
             }
             break ;
         }
         case NSStreamEventEndEncountered : //连接断开或结束
         {
             [ self closeStreams];
             break ;
         }
         case NSStreamEventErrorOccurred : //无法连接或断开连接
         {
             if ([[aStream streamError] code]) //确定code不是0……有时候正常使用时会跳出code为0的错误,但其实一点问题都没有,可以继续使用,很奇怪……
             {
                 [ self closeStreams];
                 break ;
             }
         }
         case NSStreamEventOpenCompleted :
         {
             _hasEstablished = YES ;
             break ;
         }
         case NSStreamEventHasSpaceAvailable :
         {
             break ;
         }
         case NSStreamEventNone :
         default :
             break ;
     }
}
 
//判断是否能连接到服务器。这个函数用来判断网络是否连通还好,要真的判断服务器上对应的端口是否可以连接,不是很好用来着……
-( BOOL )isServerAvailable{
     NSString *addressString = /*你的服务器地址,比如我公司地址[url]www.javista.com[/url]*/ ;
     if (!addressString) {
         return NO ;
     }
 
     SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [addressString UTF8String]);
     SCNetworkReachabilityFlags flags;
     
     BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
     CFRelease(defaultRouteReachability);
     
     if (!didRetrieveFlags)
     {
         return NO ;
     }
     
     BOOL isReachable = flags & kSCNetworkFlagsReachable;
     BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
     return (isReachable && !needsConnection) ? YES : NO ;
}
 
-( void )requestData:( NSString *)requestString whoRequest:( id )currentObject condition:( int )numCondition
{
     if (![ self isServerAvailable]) //如果无法连通到服务器
     {
         //Error Control
     }
     else
     {
         if (inStream == nil || outStream == nil )
         {
             [[Stream sharedStream] startClient];
             [[Stream sharedStream] openStreams];
             _isFirstFourBytes = YES ;
         }
         
         if (inStream != nil && outStream != nil )
         {
             _currentObject = currentObject; //记下是谁调用了requestData(记下了它的指针)
             _numCondition = numCondition; //参数,以便有时候需要区分同一个类里发来的不同请求
             if (_hasEstablished)
             {
                 NSData *requestData = [requestString dataUsingEncoding: NSUTF8StringEncoding ];
                 int dataLength = [requestData length];
                 
                 //创建前4个字节用来表示数据包长度
                 uint8_t len[4];
                 for ( int i = 0;i<4;i++)
                 {
                     len[i] = (Byte)(dataLength>>8*(3-i)&0xff);
                 }
[/i]               
                 //将这4个字节添加到数据的开头
                 NSMutableData *dataToSend = [ NSMutableData dataWithBytes:len length:4];
                 [dataToSend appendData:requestData];
                 
                 int remainingToWrite = dataLength+ 4;
                 void * marker = ( void *)[dataToSend bytes];
                 int actuallyWritten;
                 
                 while ([outStream hasSpaceAvailable]) {
                     if (remainingToWrite > 0) {
                         actuallyWritten = 0;
                         
                         if (remainingToWrite < 32768)
                             actuallyWritten = [outStream write:marker maxLength:remainingToWrite]; //不足32KB数据时发送剩余部分
                         else
                             actuallyWritten = [outStream write:marker maxLength:32768]; //每次32KB数据
                             
                         if ((actuallyWritten == -1) || (actuallyWritten == 0))
                         {
                             [ self closeStreams];
                             //Error control
                         }
                         else
                         {
                             remainingToWrite -= actuallyWritten;
                             marker += actuallyWritten;                     
                         }
                     }
                     else
                     {
                         break ;
                     }
                 }
             }
             else
             {
                 //Error Control
             }
         }
     }
}
 
-( void )manageData:( NSData *)receivedData{
     [_currentObject getData:receivedData condition:_numCondition]; //执行_currentObject指针所指向的类里的getData函数,并把收到的数据传递过去
}
 
- ( void )dealloc {
     [ super dealloc];
}
 
@end


用的时候,在调用stream的类的头文件里#import这个Stream.h,并添加一个函数叫- (void)getData:(NSData *)receivedData condition:(int)numCondition;
发送时:
?
1
[[Stream SharedStream] requestData:@ "login" /*需要发送的命令*/ whoRequest: self /*把自己的指针传递过去*/ condition:0 /*用以区分不同功能的请求*/ ];

接收完毕后Stream会调用这个类里的getData函数,这个函数写法如下:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
- ( void )getData:( NSData *)receivedData condition:( int )numCondition{
     switch (numCondition)
     {
         case 0:
             //Do something
             break ;
         case 1:
             //Do something different
             break ;
         default :
             break ;
     }
}


转自: http://www.cocoachina.com/bbs/read.php?tid=6146#

VNC Viewer建立多个图形界面,来远程访问同一个服务器(Ubuntu) 如题。目前已经有了一个VNC viewer连接,那么如果再开一个图形界面呢? 思路主要是:新建一个用户,从这个用户新建一个vnc连接,然后访问图形界面。 阅读详情

相关推荐

PSO算法介绍

结合网上的文章对PSO进行一些介绍,并附上自己复现的算法。

Witty_Hou的博客 1万+

iOS出现code:1001 reason :Stream end encountered wasclean:0

原因:被服务端踢下线

lanxingmo的专栏 3902

YOLOv11多模态融合实战:基于YOLOFuse的RGB与红外线(IR)协同检测技术解析

本文深入解析了YOLOv11多模态融合技术,重点介绍基于YOLOFuse框架的RGB与红外线(IR)协同检测方法。通过动态权重分配、跨模态特征对齐等创新设计,实现在低光照等复杂环境下的高精度目标检测,mAP提升高达37%。文章包含实战案例、训练技巧和部署方案,为计算机视觉开发者提供完整的多模态融合解决方案。

weixin_29038345的博客 290

NSStream来实现Socket

使用NSStream来实现Socket(写的不好的地方,请多批评~)这玩意儿已经折腾我小半年了,因为没有socket开发方面的经验,跌跌撞撞遇到了不少麻烦。以下是目前应用在我程序中的Stream类,真机真网络使用正常,3G和wifi都可以用。只是回调部分写的比较外行……应该还有更好的回调方式。以下代码除了SynthesizeSingleton.h外,都是从我自己的代码里一行一行挑出

wwwcybcom的专栏 2277

别再算错了!深入SAP FI后台,看懂外币清账时汇兑损益的自动计算逻辑

刚接手一家跨国企业的SAP财务模块优化项目时,我遇到了一个棘手案例:每月末外币清账产生的汇兑损益金额总是与财务团队的预期存在差异。最令人困惑的是,系统似乎"擅自"计算出了1989.11元的损益,而财务人员反复手工验算都无法复现这个数字。这让我意识到,要真正掌握SAP FI的外币处理能力,必须深入理解系统后台的汇兑损益计算逻辑——不是停留在操作层面,而是穿透到算法内核。这个过程的精妙之处在于,损益金额不是简单比较两个时点的市场汇率,而是反映业务执行全周期的汇率影响。:损益金额与手工计算不符。

weixin_32932149的博客 473

如何设计QR反激变换器

摘要:本文分析了基于GaN技术的PD适配器市场现状,重点探讨了准谐振反激变换器(QR Flyback)的工作原理及设计方法。文章首先介绍了反激变换器的三种工作模式(CCM、DCM、CRM/QR)及其特点,指出QR模式通过谷底开通技术能显著降低开关损耗。随后以65W适配器为例,详细阐述了变压器参数设计流程,包括匝比确定、原边电感计算和绕组匝数设计等关键步骤。文章强调QR反激变换器凭借高效率、小体积和低成本优势,已成为20W-65W PD适配器的主流拓扑方案,配合GaN技术进一步提升了功率密度和便携性。

m0_62868254的博客 1496

IOS Socket编程

转载自:http://www.mamicode.com/info-detail-877996.html 一、网络各个协议:TCP/IP、SOCKET、HTTP等 网络七层由下往上分别为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。 其中物理层、数据链路层和网络层通常被称作媒体层,是网络工程师所研究的对象; 传输层、会话层、表示层和应用层则被称作主机层,是用

yuhe520521的博客 300

用友U8其中一个账套提示演示期已到期-修复方法

【事件始末】 一朋友求助,反馈使用的用友U8,很多年了! 突然发现其中账套2021年的一个账套打不开,提示演示期限已到期! 但是其他账套完全正常,可以打开,没有任何问题。 不管是还原老旧备份,还是重装软件问题依旧,无法自己解决。 客户查询报表结算账期,情况比较紧急,于是求助我们。 经过多次反复琢磨和烟酒,终于于晚上23点59分给弄了出来,也总是圆满解决问题了。 【问题分析】 该用户打的是 U82X免狗补丁,估计是该补丁文件设置了 最大有效期,补丁到期了导致的。 也有可能是程序...

u010431289的博客 2万+

iOS网络编程实践--NSStream实现TCP Socket iPhone客户端

客户端我们使用iPhone应用程序,画面比较简单。点击发送按钮,给服务器发送一些字符串过去。点击接收按钮就会从服务器读取一些字符串,并且显示在画面上。有关客户端应用的UI部分不再介绍了,我们直接看代码部分,Socket客户端可以采用CFStream或NSStream实现。为了给读者介绍更多的知识,本例我们采用NSStream实现。NSStream实现采用Objective-C语言,一些面向对象的类

「智捷课堂」关东升的博客 1万+

AI Agent Harness Engineering 的“热插拔”能力:模块化设计思路

本文我会结合我在大厂做AI Agent平台的实战经验,从核心概念、架构设计、代码实现、落地实战多个维度,给大家详细讲解AI Agent Harness Engineering的核心能力——热插拔的模块化设计思路。我们会从问题根源出发,一步步搭建一个完整的支持热插拔的Agent Harness框架,包含组件抽象、注册中心、生命周期管理、配置驱动、容错机制等核心模块。

AI天才研究院 501

【工业级视觉实战】海康威视SDK + Python + YOLOv11:零延迟目标追踪系统落地指南

要在 Python 中调用海康 DLL,首先得把 C++ 的结构体 1:1 翻译过来。这是很多开发者踩坑最深的地方(指针错误、内存溢出)。import sys# 根据操作系统加载库else:# 定义设备信息结构体 (对应 C++ LPNET_DVR_DEVICEINFO_V30)("sSerialNumber", ctypes.c_byte * 48), # 序列号("byAlarmInPortNum", ctypes.c_byte), # 报警输入个数。

BUG猿的博客 226

[深入浅出Cocoa]iOS网络编程之NSStream

[深入浅出Cocoa]iOS网络编程之NSStream 罗朝辉 (http://blog.youkuaiyun.com/kesalin/) 本文遵循“署名-非商业用途-保持一致”创作公用协议   一,NSStream简介 首先来回顾下。在前文《[深入浅出Cocoa]iOS网络编程之Socket》中,提到iOS网络编程层次模型分为三层: Cocoa层:NSURL,Bonj

飘飘白云 3万+

基础入门篇 | YOLOv8 项目【训练】【验证】【推理】最简单教程 | YOLOv8必看 | 最新更新,直接打印 FPS,mAP50,75,95

三个文件搞定YOLOv8【训练】【验证】【推理】🚀🚀🚀

Coding... 2万+

IOS网络篇8之Socket收发图片(基于CFSocket NSStream)

紧接这一篇: IOS(8)网络篇7之Socket通信(传递图片和基本数据) 吧图片传输漏掉了,这里补充

关注IOS、Android网络、音视频编解码、特效、Neon算法优化,DSP等嵌入式驱动开发算法移植 1331

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

iOS网络编程之NSStream

[深入浅出Cocoa]iOS网络编程之NSStream 罗朝辉 (http://blog.youkuaiyun.com/kesalin/) 本文遵循“署名-非商业用途-保持一致”创作公用协议   一,NSStream简介 首先来回顾下。在前文《[深入浅出Cocoa]iOS网络编程之Socket》中,提到iOS网络编程层次模型分为三层: Cocoa层:NSURL,Bonj

FirstBloodFB的专栏 697

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

iOS网络编程实践–NSStream实现TCP Socket iPhone客户端

iOS网络编程实践–NSStream实现TCP Socket iPhone客户端 Posted on 2013 年 4 月 15 日 客户端我们使用iPhone应用程序,画面比较简单。点击发送按钮,给服务器发送一些字符串过去。点击接收按钮就会从服务器读取一些字符串,并且显示在画面上。 有关客户端应用的UI部分不再介绍了,我们直接看代码部分,Socket客户

zhujunyu_614的专栏 408

iOS 网络编程实践--NSStream实现TCP Socket iPhone客户端

客户端我们使用iPhone应用程序,画面比较简单。点击发送按钮,给服务器发送一些字符串过去。点击接收按钮就会从服务器读取一些字符串,并且显示在画面上。 有关客户端应用的UI部分不再介绍了,我们直接看代码部分,Socket客户端可以采用CFStream或NSStream实现。为了给读者介绍更多的知识,本例我们采用NSStream实现。NSStream实现采用Objective-C语言,一些

指间的阳光 4353

iOS 网络编程实践--NSStream实现TCP Socket iPhone客户端 .

客户端我们使用iPhone应用程序,画面比较简单。点击发送按钮,给服务器发送一些字符串过去。点击接收按钮就会从服务器读取一些字符串,并且显示在画面上。 有关客户端应用的UI部分不再介绍了,我们直接看代码部分,Socket客户端可以采用CFStream或NSStream实现。为了给读者介绍更多的知识,本例我们采用NSStream实现。NSStream实现采用Objective-C语言,一些

_听雨眠的专栏 956
上一篇: iptables禁止端口和开放端口
下一篇: CentOs 启动Red5报错 Address already in use 解决
我是一只懒虫
博客等级 码龄17年 147粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值