Socket

*********************************************

简单理解Socket 就是网络连接,可以实现两个点之间的数据通讯。

•Socket允许使用长连接,允许应用程序运行在异步模式(提高效率),只有在需要的时候才接收数据
•使用Socket,可以只传送数据本身而不用进行XML封装,大大降低数据传输的开销      在(JSON)之前出现的

iOS中常用的两种Socket类型

Ø流式Socket(SOCK_STREAM):流式是一种面向连接的Socket,针对于面向连接的TCP服务应用
Ø数据报式Socket(SOCK_DGRAM):数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用
 
•在iOS中以NSStream(流)来发送和接收数据
开发步骤
 
{

网络连接设置
  1.设置网络连接,绑定到主机和端口
  2.设置输入流和输出流的代理,监听数据流的状态
  3.将输入输出流添加至运行循环
  4.打开输入流和输出流
发送消息给服务器
有可读取字节时,读取服务器返回的内容
到达流末尾时,关闭流,同时并从主运行循环中删除
}
 

通过Scoket可以实现所有的网络功能:包括:GET、POST、PUT、DELETE

文件读取、写入(I/O)方式是以(二进制)流的方式读取的
 最主要的应用场景是:自定义的协议,编写自由的网络应用!
 
 Socket 的难点:
 1. 因为所有的(I/O)输入输出都是在一个代理方法中调用,随着自定义协议的复杂度的提高,
    程序编写难度势必要大幅度提升。
 2. 多线程的处理!
   输入流和输出流都添加到了主运行循环,如果应用过于复杂,将影响主线程程序的性能
    因此,需要使用另外一个运行循环,专门管理输入输出流。
   代理方法的工作是对数据的输入输出流进行“解析”,解析工作同样不需要影响到主线程的工作。
 
 3.多线程方面的处理,是Socket的一大难点!可以使用第三方框架GCDAsyncSocket来解决多线程问题。

连接服务器

#pragma mark 连接到服务器
- (void)connectToServer:(NSString *)hostName port:(NSInteger)port
{
// 设置网络
CFReadStreamRef readStream;
CFWriteStreamRef writeStream; // CF框架是C语言的框架
// 此方法可以连接到服务器,并分配输入流和输出流的内存空间
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)hostName, port, &readStream, &writeStream); // 记录已经分配的输入流和输出流
_inputStream = (__bridge NSInputStream *)readStream;
_outputStream = (__bridge NSOutputStream *)writeStream; // 设置代理,监听输入流和输出流中的变化
_inputStream.delegate = self;
_outputStream.delegate = self; // Scoket是建立的长连接,需要将输入输出流添加到主运行循环
// 如果不将流加入主运行循环,delegate拒绝工作
[_inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; // 打开输入流和输出流,准备开始文件读写操作
[_inputStream open];
[_outputStream open];
}

登录到聊天室

 #pragma mark 登录到聊天室
- (IBAction)login
{
NSString *hostName = _hostName.text;
NSInteger port = [_portText.text integerValue]; [self connectToServer:hostName port:port]; // 发送登录消息
NSString *msg = [NSString stringWithFormat:@"iam:%@", _nickNameText.text];
// 在网络上发送的是二进制数据
NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding]; // 发送数据,直接往输入流写数据
[_outputStream write:data.bytes maxLength:data.length];
}
 NSStream的代理方法

/**
 NSStreamEventNone = 0,                         // 无事件
 NSStreamEventOpenCompleted = 1UL << 0,         // 建立连接完成
 NSStreamEventHasBytesAvailable = 1UL << 1,     // 有可读的字节,接收到了数据,可以读了
 NSStreamEventHasSpaceAvailable = 1UL << 2,     // 可以使用输出流的空间,此时可以发送数据给服务器
 NSStreamEventErrorOccurred = 1UL << 3,         // 发生错误
 NSStreamEventEndEncountered = 1UL << 4         // 流结束事件,在此事件中负责做销毁工作
 */
#pragma mark NSStream的代理方法

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
NSLog(@"%d", eventCode); switch (eventCode) {
case NSStreamEventOpenCompleted:
NSLog(@"连接完成");
break;
case NSStreamEventHasBytesAvailable:
NSLog(@"有可读字节");
// 读从服务器接收到得数据,从输入流中读取
// 先开辟一段缓冲区以读取数据,用空间来换取程序的简单
uint8_t buffer[1024]; // read返回的是输入流缓冲区中实际存储的字节数
NSInteger len = [_inputStream read:buffer maxLength:sizeof(buffer)]; if (len > 0) { // 读到数据
// 将buffer中的数据,转换成字符串,输出
NSString *str = [[NSString alloc] initWithBytes:buffer length:len encoding:NSUTF8StringEncoding]; // 将接收到的内容添加到数组
[_dataList addObject:str]; // 刷新表格
[_tableView reloadData];
} break;
case NSStreamEventHasSpaceAvailable:
NSLog(@"可以写入数据");
break;
case NSStreamEventErrorOccurred:
NSLog(@"发生错误");
break;
case NSStreamEventEndEncountered:
NSLog(@"流结束");
// 做善后工作
// 关闭流的同时,将流从主运行循环中删除
[aStream close];
[aStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
default:
break;
}
}

GCDAsyncSocket(异步Socket)

需要导入Security.framework & CFNetwork.framework框架

// 1. Socket通讯的第一件事情——先创建一个长连接
_socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, )];

创建一个长连接

 #pragma mark - Socket代理方法
#pragma mark 连接到主机
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
NSLog(@"连接建立 %@ %@", host, [NSThread currentThread]); // 长连接建立完成后,给服务器发送 iam:昵称 通知服务器用户登录
NSString *str = [NSString stringWithFormat:@"iam:%@", _nickNameText.text];
// 网络通讯中,所有的数据都是以二进制流的模式传输的
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding]; // 将数据写入到输出流,告诉服务器用户登录
[_socket writeData:data withTimeout:- tag:];
} #pragma mark 读数据
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; if (tag == ) {
NSLog(@"登录消息 %@", str);
} else {
NSLog(@"聊天消息 %@->%ld", str, tag);
} NSLog(@"%@", [NSThread currentThread]); // 剩下的工作 绑定表格数据
[_dataList addObject:str]; // 在主线程刷新表格
dispatch_async(dispatch_get_main_queue(), ^{
[_tableView reloadData];
});
} #pragma mark 写数据
#pragma mark Socket已经把数据写给了服务器
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
// 通过Log,我们发现在给服务器写入数据时,如果指定了tag,根据tag就知道发送(写给)的是哪一类的数据
// 发现了读数据的代理方法没有被触发
NSLog(@"写数据 %ld", tag); // 尝试让socket读一下数据,读取服务器返回的内容
[_socket readDataWithTimeout:- tag:tag];
}

Socket代理方法

 #pragma mark - Action
- (IBAction)connect:(id)sender
{
NSString *hostName = _hostName.text;
int port = [[_portText text] intValue]; // 连接到主机
NSError *error = nil;
if (![_socket connectToHost:hostName onPort:port error:&error]) {
NSLog(@"%@", error.localizedDescription);
} else {
NSLog(@"OK");
}
}

Action

Socket&GCDAsyncSocket(异步Socket)的更多相关文章

  1. C# 的TCP Socket (异步方式)

    简单的c# TCP通讯(TcpListener) C# 的TCP Socket (同步方式) C# 的TCP Socket (异步方式) C# 的tcp Socket设置自定义超时时间 C# TCP ...

  2. GJM :异步Socket [转载]

    原帖地址:http://blog.csdn.net/awinye/article/details/537264 原文作者:Awinye 目录(?)[-] 转载请原作者联系 Overview of So ...

  3. Python简易聊天工具-基于异步Socket通信

    继续学习Python中,最近看书<Python基础教程>中的虚拟茶话会项目,觉得很有意思,自己敲了一遍,受益匪浅,同时记录一下. 主要用到异步socket服务客户端和服务器模块asynco ...

  4. 项目笔记---C#异步Socket示例

    概要 在C#领域或者说.net通信领域中有着众多的解决方案,WCF,HttpRequest,WebAPI,Remoting,socket等技术.这些技术都有着自己擅长的领域,或者被合并或者仍然应用于某 ...

  5. AndroidAsync :异步Socket,http(client+server),websocket和socket.io的Android类库

    AndroidAsync是一个用于Android应用的异步Socket,http(client+server),websocket和socket.io的类库.基于NIO,没有线程.它使用java.ni ...

  6. 可扩展多线程异步Socket服务器框架EMTASS 2.0 续

    转载自Csdn:http://blog.csdn.net/hulihui/article/details/3158613 (原创文章,转载请注明来源:http://blog.csdn.net/huli ...

  7. C# 实现的多线程异步Socket数据包接收器框架

    转载自Csdn : http://blog.csdn.net/jubao_liang/article/details/4005438 几天前在博问中看到一个C# Socket问题,就想到笔者2004年 ...

  8. C#实现的异步Socket服务器

    介绍 我最近需要为一个.net项目准备一个内部线程通信机制. 项目有多个使用ASP.NET,Windows 表单和控制台应用程序的服务器和客户端构成. 考虑到实现的可能性,我下定决心要使用原生的soc ...

  9. C# 异步Socket

    C# 异步Socket (BeginXXXX)服务器代码 前言: 1.最近维护公司的一个旧项目,是Socket通讯的,主要用于接收IPC(客户端)发送上来的抓拍图像,期间要保持通讯,监测数据包并进行处 ...

随机推荐

  1. [置顶] Jquery学习总结(二) jquery选择器详解

    1.基本选择器 l ID 根据元素ID选择 l Elementname 根据元素名称选择 l Classname 根据元素css类名选择 举例: <input type=”text” id=”I ...

  2. linux网站目录及Apache权限的设置

    apache服务器访问权限设置禁止所有访问:Options Indexes FollowSymLinks 改为 Option None   Apache单个或多个目录禁止访问方法   这种方法通常用来 ...

  3. java总结第二次(剩余内容)//类和对象1

    7.成员变量和局部变量 成员变量:在类中定义,用来描述对象将要有什么 局部变量:在类的方法中定义,在方法中保存临时数据 区别:作用域不同 局部变量的作用域仅限于定义它的方法 成员变量的作用域在整个类内 ...

  4. React笔记_(7)_react路由

    路由 路由(routing)是指分组从源到目的地时,决定端到端路径的网络范围的进程. 路由器当然是作为一个转发设备出现的,主要是转发数据包来实现网络互联. 那么react的路由到底指的是什么呢? 举个 ...

  5. Android 常用工具类之 ScreenUtil

    需求: 截屏 参考 :    Android开发:截屏 screenshot 功能小结 package bvb.de.openadbwireless.utils; import android.app ...

  6. Docker 端口映射问题解决

    在操作Docker容器时发现了其一个端口映射的BUG,具体表现为:开启容器时做了端口映射80:8080,即宿主机的80端口映射到容器内部的8080Jboss端口.一开始测试也没有什么问题,都可以联通, ...

  7. centos7.1-64bit延时截屏

    centos自带了截屏的软件,而且还能延时截屏. 在桌面左上角的应用程序菜单里: “应用程序”->“工具”->“截图” 设定延时秒数,点击“截图”按钮,开始截图. 完.

  8. ectouch第七讲 之ECshop模板机制整理

    网上的资源感觉还是有些用,可以看看,帮助理解,ECshop模板机制整理原文:http://blog.sina.com.cn/s/blog_6900af430100nkn8.html 一.模板引擎: E ...

  9. 《QT Creator快速入门》

    ui中的类,这样使用无法通过调试: Ui::Dialog ui(&w); w.show(); 而需要改成: Ui::Dialog ui; ui.setupUi(&w); w.show( ...

  10. ab测试大并发错误

    转载自http://xmarker.blog.163.com/blog/static/226484057201462263815783 apache 自带的ab工具测试,当并发量达到1000多的时候报 ...