博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IOS-Socket
阅读量:5269 次
发布时间:2019-06-14

本文共 14330 字,大约阅读时间需要 47 分钟。

 

Socket描述了一个IP、端口对。它简化了程序员的操作,知道对方的IP以及PORT就可以给对方发送消息,再由服务器端来处理发送的这些消息。所以,Socket一定包含了通信的双发,即客户端(Client)与服务端(server)。

1)服务端利用Socket监听端口;

2)客户端发起连接;

3)服务端返回信息,建立连接,开始通信;

4)客户端,服务端断开连接。

 

1套接字(socket)概念

套接字(socket)是通信的基石(通信连接),是支持TCP/IP协议的网络通信的基本操作单元。

客户端与服务器之间的数据交互需要一个双向的通信连接

应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应 用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

2 建立socket连接

建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。

套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。

客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发 给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

 

4、SOCKET连接与TCP连接

创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。

 

5、Socket连接与HTTP连接

由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网 络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。

而HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。

 

 

 

一、网络编程

网络模型
OSI(开放系统互联Open System Interconnection)TCP/IP参考模型
 
网络通讯要素
IP地址
端口号
传输协议
 
TCP\UDP:数据传输方式
HTTP\XMPP:数据传输格式
 
二、网络通讯要素
IP地址(唯一标示网络设备的):
网络中设备的标示
不易记忆,可以用主机名
本地回环地址:127.0.0.1 主机名:localhost
端口号(定位程序)
用于标示进程的逻辑地址,不同进程的标示
有效端口:0~65535,其中0~1024由系统使用或者保留端口,开发中不要使用1024以下的端口
传输协议(用什么样的方式进行交互)
通讯的规则
常见协议:TCP、UDP
 
URL(统一资源定位)
 
三、TCP & UDP
TCP(传输控制协议)
建立连接,形成传输数据的通道
在连接中进行大数据传输(数据大小不收限制)
通过三次握手完成连接,是可靠协议,安全送达
必须建立连接,效率会稍低

 

UDP(用户数据报协议)
将数据及源和目的封装成数据包中,不需要建立连接
每个数据报的大小限制在64K之内
因为无需连接,因此是不可靠协议
不需要建立连接,速度快
 
四、Socket(套接字)
1.Socket就是为网络服务提供的一种机制
通信的两端都是Socket
网络通信其实就是Socket间的通信
数据在两个Socket间通过IO传输
 
2.实现Socket服务端监听
实现socket的监听方法
(1)使用C语言实现,
(2)使用CocoaAsyncSocket第三方框,内部是对C的封装
Telnet命令 telnet host port/telnet 192.168.10.10 5288
telnet命令是连接服务器上的某个端口对应的服务
 
3.Socket层上的协议
Socket层上的协议指的数据传输的格式
HTTP协议
传输格式:假设:
这是假设,实际
http
的格式不是这样的。
http1.1,content-type:multipart/form-data,content-length:188,body:username=zhangsan&password=123456
 
XMPP协议,是一款即时通讯协议
 可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息

  传输格式:

  <from>zhangsan<from>

   <to>lisi<to>

   <body>一起吃晚上</body>

 

自定义即时通讯协议,json格式

{

“from”:”zhangsan”,

”to”:”lisi”,

”body”:”中午一起吃饭”

}

 
 
 
五、Socket 通讯流程图
 
六、使用Socket开发网络通讯
在Web服务(WebServices=>XML)大行其道的今天,调用Web服务的代价是高昂的,尤其是仅仅是抓取少量数据的时候尤其如此。而使用Socket,可以只传送数据本身而不用进行XML封装,大大降低数据传输的开销(JSON)
 
Socket允许使用长连接,允许应用程序运行在异步模式(提高效率),只有在需要的时候才接收数据
 
七、iOS中常用的两种Socket类型
流式Socket(SOCK_STREAM):流式是一种面向连接的Socket,针对于面向连接的TCP服务应用
数据报式Socket(SOCK_DGRAM):数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用
 
八、在iOS中流式Socket连接的方法
在iOS中以NSStream(流)来发送和接收数据
可以设置流的代理,对流状态的变化做出相应
连接建立
接收到数据
连接关闭
 
1.NSStream:数据流的父类,用于定义抽象特性,例如:打开、关闭代理,NSStream继承自CFStream(Core Foundation)
2.NSInputStream:NSStream的子类,用于读取输入
3.NSOutputStream:NSSTream的子类,用于写输出
 
九、开发步骤
1.网络连接设置
   1>设置网络连接,绑定到主机和端口
   2>设置输入流和输出流的代理,监听数据流的状态
   3>将输入输出流添加至运行循环
   4>打开输入流和输出流
2.发送消息给服务器
3.有可读取字节时,读取服务器返回的内容
4.到达流末尾时,关闭流,同时并从主运行循环中删除
 
十、工作流程

服务器的工作流程:首先调用socket函数创建一个Socket,然后调用bind函数将其与本机地址以及一个本地端口号绑定,然后调用listen在相应的socket上监听,当accpet接收到一个连接服务请求时,将生成一个新的socket。服务器显示该客户机的IP地址,并通过新的socket向客户端发送字符串” hi,I am server!”。最后关闭该socket。

客户端的工作流程:首先调用socket函数创建一个Socket,然后调用bind函数将其与本机地址以及一个本地端口号绑定,请求连接服务器,通过新的socket向客户端发送字符串” hi,I am client!”。最后关闭该socket。 UDPSocket的具体实现

服务器的工作流程:首先调用socket函数创建一个Socket,然后调用bind函数将其与本机地址以及一个本地端口号绑定,接收到一个客户端时,服务器显示该客户端的IP地址,并将字串返回给客户端。

客户端的工作流程:首先调用socket函数创建一个Socket,填写服务器地址及端口号,从标准输入设备中取得字符串,将字符串传送给服务器端,并接收服务器端返回的字符串。最后关闭该socket。

 
代码:
1 //  2 //  ServertListener.h  3 //  服务器监听  4 //  5 //  Created by Vincent_Guo on 15/9/11.  6 //  Copyright (c) 2015年 稳食哥 wechat:vg-ios. All rights reserved.  7 //  8   9 #import 
10 11 @interface ServertListener : NSObject 12 13 /**开始监听*/ 14 -(void)start; 15 16 @end 17 18 19 // 20 // ServertListener.m 21 // 服务器监听 22 // 23 // Created by Vincent_Guo on 15/9/11. 24 // Copyright (c) 2015年 稳食哥 wechat:vg-ios. All rights reserved. 25 // 26 27 #import "ServertListener.h" 28 #import "GCDAsyncSocket.h" 29 30 @interface ServertListener()
31 32 /** 33 * 服务端Socket 34 */ 35 @property(nonatomic,strong)GCDAsyncSocket *serverSocket; 36 37 /* 38 * 所有的客户端 39 */ 40 @property(nonatomic,strong)NSMutableArray *clientSockets; 41 42 @property(nonatomic,strong)NSMutableString *log;//日志 43 @end 44 45 @implementation ServertListener 46 47 -(NSMutableString *)log{ 48 if (!_log) { 49 _log = [NSMutableString string]; 50 } 51 52 return _log; 53 } 54 55 -(NSMutableArray *)clientSockets{ 56 if (!_clientSockets) { 57 _clientSockets = [NSMutableArray array]; 58 } 59 60 return _clientSockets; 61 } 62 63 -(instancetype)init{ 64 if (self = [super init]) { 65 self.serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)]; 66 } 67 68 return self; 69 } 70 71 72 -(void)start{ 73 NSError *error = nil; 74 BOOL success = [self.serverSocket acceptOnPort:5288 error:&error]; 75 if (success) { 76 NSLog(@"5288端口开启成功,并监听客户端请求连接..."); 77 }else{ 78 NSLog(@"5288端口开启失..."); 79 } 80 } 81 82 #pragma mark -代理 83 -(void)socket:(GCDAsyncSocket *)serverSocket didAcceptNewSocket:(GCDAsyncSocket *)clientSocket{ 84 85 NSLog(@"%@ IP: %@: %zd 客户端请求连接...",clientSocket,clientSocket.connectedHost,clientSocket.connectedPort); 86 // 1.将客户端socket保存起来 87 [self.clientSockets addObject:clientSocket]; 88 89 // 2.一旦同意连接,监听数据读取,如果有数据会调用下面的代理方法 90 [clientSocket readDataWithTimeout:-1 tag:0]; 91 92 // 3.返回 "服务" 选项 93 NSMutableString *options = [NSMutableString string]; 94 [options appendString:@"欢迎来到10086在在线服务 请输入下面的数字选择服务\n"]; 95 [options appendString:@"[0]在线充值\n"]; 96 [options appendString:@"[1]在线投诉\n"]; 97 [options appendString:@"[2]优惠信息\n"]; 98 [options appendString:@"[3]special services\n"]; 99 [options appendString:@"[4]退出\n"];100 NSData *data = [options dataUsingEncoding:NSUTF8StringEncoding];101 [clientSocket writeData:data withTimeout:-1 tag:0];102 }103 104 105 106 -(void)socket:(GCDAsyncSocket *)clientSocket didReadData:(NSData *)data withTag:(long)tag{107 108 // 1.客户端 传递的数据 转成字符串109 NSString *clientStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];110 111 NSString *log = [NSString stringWithFormat:@"IP:%@ %zd data:%@\n",clientSocket.connectedHost,clientSocket.connectedPort, clientStr];112 NSLog(@"%@",log);113 [self.log appendString:log];114 [self.log writeToFile:@"/Users/Fung/Desktop/server.log" atomically:NO encoding:NSUTF8StringEncoding error:nil];115 116 NSInteger serverCode = [clientStr integerValue];117 switch (serverCode) {118 case 0:119 [self writeDataWithSocket:clientSocket str:@"充值服务暂停,系统维护...\n"];120 break;121 case 1:122 [self writeDataWithSocket:clientSocket str:@"投诉服务暂停,系统维护\n"];123 break;124 case 2:125 [self writeDataWithSocket:clientSocket str:@"最近优惠服务,充一万,送5千。。\n"];126 break;127 case 3:128 [self writeDataWithSocket:clientSocket str:@"你傻啊,还真以为有特殊服务...\n"];129 break;130 case 4:131 [self exitWithSocket:clientSocket];132 break;133 134 default:135 [self writeDataWithSocket:clientSocket str:@"请说人话...\n"];136 break;137 }138 139 // 2.监听数据读取140 [clientSocket readDataWithTimeout:-1 tag:0];141 }142 143 144 145 -(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{146 147 NSLog(@"数据发送成功..");148 }149 150 -(void)exitWithSocket:(GCDAsyncSocket *)clientSocket{151 [self writeDataWithSocket:clientSocket str:@"成功退出\n"];152 [self.clientSockets removeObject:clientSocket];153 154 NSLog(@"当前在线用户个数:%ld",self.clientSockets.count);155 }156 157 #pragma mark -私有方法158 #pragma mark -写数据159 -(void)writeDataWithSocket:(GCDAsyncSocket *)clientSocket str:(NSString *)str{160 161 [clientSocket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];162 163 }164 165 @end
1 // 2 //  main.m 3 //  服务器监听 4 // 5 //  Created by Vincent_Guo on 15/9/11. 6 //  Copyright (c) 2015年 稳食哥 wechat:vg-ios. All rights reserved. 7 // 8  9 #import 
10 #import "ServertListener.h"11 12 int main(int argc, const char * argv[]) {13 @autoreleasepool {14 // insert code here...15 NSLog(@"Hello, World!");16 // 1.创建服务监听器17 ServertListener *listener = [[ServertListener alloc] init];18 19 // 2.开始监听20 [listener start];21 22 // 开启主运行循环23 [[NSRunLoop mainRunLoop] run];24 }25 return 0;26 }

 

群聊客户端
1 //  2 //  ViewController.m  3 //  IOS_0406_群聊客户端  4 //  5 //  Created by ma c on 16/4/6.  6 //  Copyright © 2016年 博文科技. All rights reserved.  7 //  实现聊天室  8   9 #import "ViewController.h" 10 #import "GCDAsyncSocket.h" 11  12 @interface ViewController ()
13 14 @property (weak, nonatomic) IBOutlet UITextField *textField; 15 - (IBAction)send:(id)sender; 16 @property (weak, nonatomic) IBOutlet UITableView *tableView; 17 @property (nonatomic, strong) GCDAsyncSocket *clientSocket; 18 @property (nonatomic, strong) NSMutableArray *dataSource; 19 20 21 @end 22 23 @implementation ViewController 24 25 - (void)viewDidLoad { 26 [super viewDidLoad]; 27 //1.连接到群服务器 28 //1.1创建一个客户端的socket对象 29 GCDAsyncSocket *clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)]; 30 self.clientSocket = clientSocket; 31 //1.2发送连接请求 32 NSError *error = nil; 33 [clientSocket connectToHost:@"127.0.0.1" onPort:5288 error:&error]; 34 if (!error) { 35 NSLog(@"%@",error); 36 } 37 } 38 39 #pragma mark - GCDAsyncSocketDelegate 40 //连接成功 41 - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port 42 { 43 NSLog(@"连接成功"); 44 //监听读取数据 45 [sock readDataWithTimeout:-1 tag:0]; 46 } 47 //断开连接 48 - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err 49 { 50 NSLog(@"断开连接"); 51 } 52 53 - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag 54 { 55 NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 56 NSLog(@"%@",str); 57 //把消息添加到数据源 58 if (str) { 59 [self.dataSource addObject:str]; 60 61 //主线程中刷新表格 62 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 63 [self.tableView reloadData]; 64 }]; 65 } 66 //读完数据之后,继续监听读取数据 67 [sock readDataWithTimeout:-1 tag:0]; 68 69 } 70 71 72 73 #pragma mark - UITableViewDataSource 74 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 75 { 76 return self.dataSource.count; 77 } 78 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 79 { 80 static NSString *ID = @"cell"; 81 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; 82 //显示文字 83 cell.textLabel.text = self.dataSource[indexPath.row]; 84 return cell; 85 } 86 87 88 89 - (IBAction)send:(id)sender { 90 91 NSString *str = self.textField.text; 92 93 if (str.length == 0) { 94 NSLog(@"无数据发送"); 95 } else { 96 //发送数据 97 [self.clientSocket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0]; 98 //把数据添加到数据源 99 [self.dataSource addObject:str];100 [self.tableView reloadData];101 }102 }103 104 #pragma mark - 懒加载105 - (NSMutableArray *)dataSource106 {107 if(!_dataSource){108 _dataSource = [NSMutableArray array];109 110 }111 return _dataSource;112 }113 114 @end

群聊服务器

1 // 2 //  ChatServer.m 3 //  IOS_0406_群聊天服务端 4 // 5 //  Created by ma c on 16/4/6. 6 //  Copyright © 2016年 博文科技. All rights reserved. 7 // 8  9 #import "ChatServer.h"10 #import "GCDAsyncSocket.h"11 12 @interface ChatServer ()
13 14 @property (nonatomic, strong) GCDAsyncSocket *serverSocket;15 //客户端所有socket对象16 @property (nonatomic, strong) NSMutableArray *clients;17 18 @end19 20 @implementation ChatServer21 22 - (void)start23 {24 //1.创建一个监听者对象25 GCDAsyncSocket *serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];26 //2.绑定端口并监听27 NSError *error = nil;28 [serverSocket acceptOnPort:5288 error:&error];29 if (!error) {30 NSLog(@"10086服务开启成功");31 }else{32 NSLog(@"10086服务开启失败");33 }34 self.serverSocket = serverSocket;35 }36 #pragma mark - GCDAsyncSocketDelegate37 - (void)socket:(GCDAsyncSocket *)severSocket didAcceptNewSocket:(GCDAsyncSocket *)clientSocket38 {39 //NSLog(@"\nsever:%@----client:%@",severSocket, clientSocket);40 NSLog(@"host:%@, port:%d", clientSocket.connectedHost, clientSocket.connectedPort);41 //1.保存客户端的socket42 [self.clients addObject:clientSocket];43 NSLog(@"已有%ld人上线",self.clients.count);44 //2.监听客户端有没有数据上传45 //timeout=-1代表不超时 tag标识作用46 [clientSocket readDataWithTimeout:-1 tag:0];47 48 }49 //读取客户端请求的数据50 -(void)socket:(GCDAsyncSocket *)clientSocket didReadData:(NSData *)data withTag:(long)tag51 {52 //NSLog(@"client:%@",clientSocket);53 NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];54 NSLog(@"%@",str);55 for (GCDAsyncSocket *socket in self.clients) {56 if (socket != clientSocket) {57 //处理请求,返回数据给客户端58 [socket writeData:data withTimeout:-1 tag:0];59 }60 }61 //每次读完数据后都要调用一次监听方法62 [clientSocket readDataWithTimeout:-1 tag:0];63 }64 65 #pragma mark - 懒加载66 - (NSMutableArray *)clients67 {68 if(!_clients){69 _clients = [NSMutableArray array];70 71 }72 return _clients;73 }74 @end

 

 
 
 
 

转载于:https://www.cnblogs.com/oc-bowen/p/5266277.html

你可能感兴趣的文章
ssm框架之将数据库的数据导入导出为excel文件
查看>>
语音识别中的MFCC的提取原理和MATLAB实现
查看>>
验证组件FluentValidation的使用示例
查看>>
0320-学习进度条
查看>>
解决windows系统的oracle数据库不能启动ora-00119和ora-00130的问题
查看>>
ip相关问题解答
查看>>
MetaWeblog API Test
查看>>
反弹SHELL
查看>>
关闭Chrome浏览器的自动更新和升级提示
查看>>
移动、尺寸改变
查看>>
poj2255Tree Recovery【二叉树重构】
查看>>
tcpcopy 流量复制工具
查看>>
vue和react的区别
查看>>
第十一次作业
查看>>
负载均衡策略
查看>>
微信智能开放平台
查看>>
ArcGIS Engine 中的绘制与编辑
查看>>
Oracle--通配符、Escape转义字符、模糊查询语句
查看>>
c# 文件笔记
查看>>
第一页 - 工具的使用(webstorm)
查看>>