iOS 网络编程 TCP/UDP HTTP

1、HTTP协议的主要特色:css

1. CS模式 
2. 简单快速:只须要传送请求方法和路径。(经常使用方法有GET,HEAD,POST) 
3. 灵活:任意对象均可以,类型由Content-Type加以标记 
4. 无链接、无状态 即每次链接只处理一个请求,对于事务处理没有记忆能力 
http表示要经过HTTP协议来定位网络资源;host表示合法的Internet主机域名或者IP地址;port制定一个端口号,为空时使用缺省端口号80;abs_path指定请求资源的URI;若是URL中没有给出abs_path,那么当它做为请求URI时,必须以“/”的形式给出(此过程由浏览器完成)。ios

2、TCP/UDP区别和联系 
1.TCP是面向链接的可靠的传输控制协议,UDP是面向非链接的用户数据报协议. 
2.TCP(三次握手保证相对可靠性)可传大量数据,速度相对比较慢,UDP一次性传输少许对可靠性要求不高的数据,速度比较快 
tcp通常用于音频、视频等数据的传输,资源能耗比较小,对可靠性要求不高,即便丢失一两条数据也不会产生太大影响。git

3、Socket链接和Http链接的区别 
1.http是基于socket之上的,socket是一套完成tcp和udp协议的接口 
2.HTTP协议:简单对象访问协议,对应于应用层 ,HTTP协议是基于TCP链接的 
3.tcp协议: 对应于传输层 
4.ip协议: 对应于网络层  
TCP/IP是传输层协议,主要解决数据如何在网络中传输;而HTTP是应用层协议,主要解决如何包装数据。 
Socket是对TCP/IP协议的封装,Socket自己并非协议,而是一个调用接口(API),经过Socket,咱们才能使用TCP/IP协议。 
http是短链接,客户端向服务端发送一次请求,服务端响应后链接即断掉;socket是长链接,通常状况下,若是服务器端或者客户端主机down了,网络故障,或者二者长时间没有数据传输,链接可能会断。因此当以个socket链接中没有数据的传输,为了维持链接须要发送心跳消息。github

4、三次握手的过程再也不赘述,主要来了解下socket创建网络链接的步骤 
创建socket链接至少须要一堆套接字,其中一个运行于客户端,另外一个运行于服务端(ClientSocket、ServerSocket) 
套接字创建链接的过程分为三步:服务器监听、客户端请求、链接确认 
1。服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待链接的状态,实时监控网络状态,等待客户端的链接请求。 
2。客户端请求:指客户端的套接字提出链接请求,要链接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要链接的服务器的套接字,指出服务器端套接字的地址端口号,而后就向服务器端套接字提出链接请求。 
3。链接确认:当服务器端套接字监听到或者说接收到客户端套接字的链接请求时,就响应客户端套接字的请求,创建一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式创建链接。而服务器端套接字继续处于监听状态,继续接收其余客户端套接字的链接请求。编程

5、HTTP链接最显著的特色是客户端发送的每次请求都须要服务器回送响应,在请求结束后,会主动释放链接。从创建链接到关闭链接的过程称为“一次链接”。数组

 

AsyncSocket是IOS下专门用于socket套接字开发的开源库,它封装了CFNetwork/BSD Socket.提供了异步的开发模型和简便的开发接口。它支持TCP/UDP,支持UDP组播 

AsyncSocket支持GCD/Runloop模式 支持ARC 使用时须要增长两个库 CFNetwork.frame和Security.framexcode

6、UDP编程 
server端流程: 
1. socket建立套接字 
2. bind绑定port 
3. recv接收、send发送数据 
4. close关闭socket套接字 
client端流程 
1.socket建立套接字 
2.bind绑定port端口(可选) 
3. recv接收 send发送数据 
4. close关闭socket套机制浏览器

UDP编程涉及到 ip和字符串的转化以下
/*绑定ip地址 */ inet_pton(AF_INET,"192.168.101.2",&addr.sin_addr); /*把地址sin_addr转化成字符串ipBuf*/ inet_ntop(AF_INET,&srcaddr.sin_addr,ipBuf,16);

UDP基本API 
1. 建立UDP的套接字int sd = socket(AF_INET,SOCK_DGRAM,0); 
2. 设置端口能够重用 int nOptval = 1;  
ret = setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,(const void*)&nOptval,sizeof(int));
 
3. 绑定端口 ret = bind(sd,(struct sockaddr *)&addr,addrlen); 
4. 给某个地址发送数据ssize_t sendLen = sendto(sd,res,strlen(res),0,(struct sockaddr *)&srcaddr,sizeof(srcaddr)); 
5. 接收来自sd的数据ssize_t recvLen = recvfrom(sd,&info,sizeof(info),0,(struct sockaddr *)&srcaddr,&addrlen); 
6. 关闭套接字 Close(sd);安全

UDP 编程示例 
server端 : 新建工程 Cococa Application 引入AsyncSocket 
引入头文件 #import “AsyncUdpSocket.h” 以及代理 AsyncUdpSocketDelegate服务器

_udpSocketServer = [[AsyncUdpSocket alloc] initWithDelegate:self]; //绑定端口 用于标识socket对象 if(![_udpSocketServer bindToPort:5678 error:nil]){ NSLog(@"绑定失败"); } //监听状态 是否有客户端发送来的消息 [_udpSocketServer receiveWithTimeout:-1 tag:100]; 

代理回调

#pragma maek- socketDelegate //收到消息时的回调 -(BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{ NSLog(@"port:%d",port); NSString* messege = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"recieve:%@",messege); [sock receiveWithTimeout:-1 tag:200]; return YES; }

上述代码便可实现简单的UDPServer端 

UDPClient 代码(简单示例) 
一样的要声明UDP对象 而后发送消息

NSString* messege = @"UDPClient 消息"; NSData* data = [messege dataUsingEncoding:NSUTF8StringEncoding]; /* *发送消息 host: 制定服务器的ip地址 port: 服务器的端口 -1 不限时发送 tag 对这次操做的标记 */ [_clientSocket sendData:data toHost:@"127.0.0.1" port:5678 withTimeout:-1 tag:0]; /*发送成功的回调方法是*/ - (void)onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag{ NSLog(@"发送成功!"); } 

TCP编程 
server端流程 
1. socket建立socket套接字 
2. bind绑定port端口 
3. listen监听端口 
4. close关闭socket套机制 
client端流程 
1.socket建立套接字 
2.bind绑定port端口(可选) 
3.connect服务器端口 
4.close关闭socket套机制

了解下 tcp的重传策略: TCP用于控制数据段是否须要重传的依据是设立重发定时器。在发送一个数据段的同时启动一个重发定时器,AC(Ackonowlegement)就关闭该定时器,若是在定时器超时前没有收到确认,则重传该数据段。在选择重发时间的过程当中,TCP必须具备自适应性。它须要根据互联网当时的通讯状况,给出合适的数据重发。

TCP编程实例 
server  
1.引入头文件 #import “AsyncSocket.h” AsyncSocketDelegate

_tcpServer = [[AsyncSocket alloc]initWithDelegate:self]; //服务端对应的ip地址和端口,_serverSocket负责监听是否有客户端接入 //[_tcpServer acceptOnInterface:@"127.0.0.1" port:5678 error:nil]; //服务端负责监听是否有客户端接入此端口,host能够缺省不写 [_tcpServer acceptOnPort:5678 error:nil];

2.发现有客户端接入时响应

-(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket{ NSLog(@"new socket host:%@ port:%d",newSocket.connectedHost,newSocket.connectedPort); //将新生成的socket对象加入数组中 [_array addObject:newSocket]; //负责不限时的监听客户端是否发送消息过来 [newSocket readDataWithTimeout:-1 tag:1]; }

3 收到客户端发送过来的消息时

-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"receive:%@",message); //告诉sock,继续监听客户端 [sock readDataWithTimeout:-1 tag:2]; } 

4链接的客户端长时间不活跃时触发下面的方法

- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err{ NSLog(@"willDisconnect!"); }

5 断开链接时

//已经断开链接 - (void)onSocketDidDisconnect:(AsyncSocket *)sock{ NSLog(@"%s",__FUNCTION__);//__FUNCTION__ 可以打印出当前函数的名称,通常用于对程序进行暴力调试时 }

client编程 
1. 初始化一个AsyncSocket对象 
_clientSocket = [[AsyncSocket alloc] initWithDelegate:self]; 
2. 与指定的服务器进行链接

if (!_clientSocket) { //建立一个客户端对象,并设置delegate _clientSocket = [[AsyncSocket alloc] initWithDelegate:self]; } //先判断是否与指定服务器链接 if ([_clientSocket isConnected]) { //断开链接 [_clientSocket disconnect]; } //与指定服务器链接 //connectToHost 服务端的ip地址 //port 服务端的端口:端口的值可随意约定 [_clientSocket connectToHost:@"127.0.0.1" onPort:5678 error:nil]; 

3.发送消息

NSString *message = @"hello server!"; //将数据转换成data NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding]; //将data发给服务器 //data 发送的数据, timeout:-1 不限时发送, tag,对这次交互的标记 [_clientSocket writeData:data withTimeout:-1 tag:0]; 

4.回调方法

//当客户端与服务端链接成功时,调用此方法
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{ NSLog(@"与服务器:%@ %d 相链接",host,port); } //消息发送成功后,调用此方法 - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{ NSLog(@"send!"); } 

点解此处下载 demo 
今天主要是tcp和udp的编程 明天更新 http和流媒体

 

 

iOS中的TCP,UDP,socket的学习

先贴一下以前学习过的代码:

加入CFNetwork.framework,去github上下载AsyncSocket

TCP

- (void)viewDidLoad
{
    [super viewDidLoad];

    recvArray = [[NSMutableArray alloc] init];
    //服务端
    recvSocket = [[AsyncSocket alloc] initWithDelegate:self];
    //客户端
    sendSocket = [[AsyncSocket alloc] initWithDelegate:self];
    
    //服务端开始等待别的客户端的连接
    //65535     >5000
    [recvSocket acceptOnPort:5678 error:nil];
    //那么何时接受到了连接
}

//调用这个方法就证实接受到了一个连接
- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket{
    [recvArray addObject:newSocket];
    //等待客户端发送数据
    [newSocket readDataWithTimeout:-1 tag:100];
    //何时读取到了数据
}

//调用这个方法就证实接受到了客户端发送的数据
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
    NSString* str = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
    contentView.text = [NSString stringWithFormat:@"%@\n对方说:%@",contentView.text,str];
    //继续等待服务端发送数据
    [sock readDataWithTimeout:-1 tag:100];
}

//=============

//调用这个方法的时候,就证实连接成功
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{

}

- (void)sendText:(id)sender{
    //若是没连接,那么去连接服务端
    if (sendSocket.isConnected == NO) {
        [sendSocket connectToHost:ipField.text onPort:5678 withTimeout:60 error:nil];
        //何时知道连接成功
    }
    
        
    NSData* data = [sendField.text dataUsingEncoding:NSUTF8StringEncoding];
    //发送数据
    [sendSocket writeData:data withTimeout:60 tag:100];
    //何时知道数据发送成功
}


//调用这个方法,就证实数据发送成功
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{
    
}

UDP

 

- (void)viewDidLoad
{
    [super viewDidLoad];
	
    recvSocket = [[AsyncUdpSocket alloc] initWithDelegate:self];
    //绑定端口
    [recvSocket bindToPort:5888 error:nil];
    
    sendSocket = [[AsyncUdpSocket alloc] initWithDelegate:self];
    [sendSocket bindToPort:5999 error:nil];
    
    //等待接受数据
    [recvSocket receiveWithTimeout:-1 tag:100];
    //何时接受到了数据
    
}
//调用这个方法的时候证实接收到了数据
- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{
    
    NSString* str = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
    contentView.text = [NSString stringWithFormat:@"%@\n%@:%@",contentView.text,host,str];
    [recvSocket receiveWithTimeout:-1 tag:100];
    
    return YES;
}

- (void)sendText:(id)sender{
    NSData* data = [sendField.text dataUsingEncoding:NSUTF8StringEncoding];
    //发送数据
    [sendSocket sendData:data toHost:ipField.text port:5888 withTimeout:60 tag:100];
    //何时发送成功
}

//这里就发送成功了
- (void)onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag{
    
}
首先说一下他们直接的联系,UDP和TCP就像声明的一个协议,是须要传送的东西也就是内容,而scoket就像是一个通道,用于传送这些内容,也就是用socket来实现。
UDP:UDP是一种面向无链接的用户数据报服务(user data protocol),不须要和服务器也能交互,只须要知道ip和监听端口,不须要连接没有目的的socket,只是将数据报投递出去,无论接收方是否成功接收到,所以是一种不可靠的传输,可能会形成数据丢包,但因为这些特征,传输效率要优于TCP。

TCP:TCP是一种面向链接的传输控制协议(transform contorl protocol),必需要和服务器交互,具备高安全性,可靠性,须要和服务器进行三次握手,能根据具体网络拥堵状况进行延时。
Socket:Socket有两种链接操做方式,面向链接的和面向无链接的。使用UDP就是面向无链接的,使用TCP就是面向链接的。使用UDP无须要指定一个socket目的地,而是用TCP必需要指定一个socket目的地,须要进行预连接,不然链接不到。
socket就像是API,二UDP/TCP就是协议,使用scoket来实现内容的传送。

 TCP的3次握手:

创建起一个TCP链接须要通过“三次握手”:

第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时本身也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

握手过程当中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP链接一旦创建,在通讯双方中的任何一方主动关闭链接以前,TCP 链接都将被一直保持下去。断开链接时服务器和客户端都可以主动发起断开TCP链接的请求,断开过程须要通过“四次握手”(过程就不细写了,就是服务器和客户端交互,最终肯定断开)

 

网络上已经有编写好的开源类库GCDAsyncSocket 和GCDAsyncUdpSocket  这是GCD版的  比AsyncSocket 和AsyncUdpSocket估计要好用点 用法也很简单,跟http很相似  只要指定服务器的ip和端口 而后再实现各类回调就行,原生态实现正在摸索。。。。。socket默认状况下就是采用TCP协议,建立以后通讯双方的socket会一直保持链接,除非手动close或由于网络缘由close,因此,此种情况对服务器而言是有必定资源消耗的,这种模式只适应与对服务器小规模的访问,特别是对于实时性很高的应用,如视频直播、呼叫系统等,而http通常都是短链接的,一次请求完以后客户端便会于服务端端开链接
   http是凌驾于socket之上的高级协议,而socket是比较底层的通信方式,只是创建了一个链接通道,具体上面传输什么样的数据,按照什么格式传输,须要你本身定义,因此这就须要从新编写定义服务端与客户端的所应遵循的规定,而http已经被前人们定义使用过了

先去github的网站下载最新的包,而后先看看介绍。写的比较详细了

https://github.com/robbiehanson/CocoaAsyncSocket/wiki/Intro_GCDAsyncSocket

网上不少都是老版本的帖子。官方已经推出了GCDAsyncSocket来代替之前老的AsyncSocket。

个人项目是no-ARC的,这个框架只有arc的版本。因此引入GCDAsyncSocket的.h和.m文件后,修改xcode中项目的属性。

1)targets中“build settings”中找到Compiler for c/c++/Objective-c的选项。改成Apple LLVM compiler 3.0 只要是3.0或以上就能够;

2)在“build phases”中“compile sources”中找到GCDAsyncSocket.m,增长参数-fobj-arc;

3)引入GCDAsyncSocket所须要的框架,CFNetwork和security这两个。

知识补充:

使用Socket进行C/S结构编程,链接过程

 1

服 务器端监听某个端口是否有链接请求。服务器端程序处于堵塞状态,直到客户端向服务器端发出链接请求,服务器端接受请求程序才能向下运行。一旦链接创建起 来,经过Socket能够得到输入输出流对象。借助于输入输出流对象就能够实现与客户端的通信,最后不要忘记关闭Socket和释放一些资源(包括:关闭 输入输出流)。

客户端流程是先指定要通信的服务器IP地址、端口和采用的传输协议(TCP或UDP),向服务器发出链接请求,服务器有应答请求以后,就会创建链接。以后与服务器端是同样的了。

在iOS中,客户端Socket编程可使用的技术有三种:

1 使用NSStream。面向Objective-C语言的实现,由苹果提供的Foundation框架提供的API;

2 使用CFStream。面向C语言的实现,由苹果提供的Core Foundation框架提供的API;

BSD Socket。 也叫伯克利套接字(Berkeley Socket),是Unix平台下普遍使用的Socket编程。它是面向C语言实现 的,彻底使用C编写,使用起来比较麻烦。它是伯克利加州大学(University of California, Berkeley)的学生开发的。

在iOS中,服务器端Socket编程可使用技术有二种:

1 使用CFStream。面向C语言的实现,由苹果提供的Core Foundation框架提供的API;

2 BSD Socket。 也叫伯克利套接字(Berkeley Socket),是Unix平台下普遍使用的Socket编程。它是面向C语言实 现的,彻底使用C编写的,使用起来比较麻烦。它是伯克利加州大学(University of California, Berkeley)的学生开发的。

 
相关文章
相关标签/搜索