网络七层由下往上分别为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
OSI七层网络模型
|
TCP/IP四层概念模型
|
对应网络协议
|
应用层(Application)
|
应用层
|
TFTP, FTP, NFS, WAIS
|
表示层(Presentation)
|
Telnet, Rlogin, SNMP, Gopher
|
|
会话层(Session)
|
SMTP, DNS
|
|
传输层(Transport)
|
传输层
|
TCP, UDP
|
网络层(Network)
|
网际层
|
IP, ICMP, ARP, RARP, AKP, UUCP
|
数据链路层(Data Link)
|
网络接口
|
FDDI, Ethernet, Arpanet, PDN, SLIP, PPP
|
物理层(Physical)
|
IEEE 802.1A, IEEE 802.2到IEEE 802.11
|
网络七层协议
应用层:
1.用户接口、应用程序;
2.Application典型设备:网关;
3.典型协议、标准和应用:TELNET、FTP、HTTP
表示层:
1.数据表示、压缩和加密presentation
2.典型设备:网关
3.典型协议、标准和应用:ASCLL、PICT、TIFF、JPEG|MPEG
4.表示层相当于一个东西的表示,表示的一些协议,比如图片、声音和视频MPEG。
会话层:
1.会话的建立和结束;
2.典型设备:网关;
3.典型协议、标准和应用:RPC、SQL、NFS、X WINDOWS、ASP
传输层:
1.主要功能:端到端控制Transport;
2.典型设备:网关;
3.典型协议、标准和应用:TCP、UDP、SPX
网络层:
1.主要功能:路由、寻址Network;
2.典型设备:路由器;
3.典型协议、标准和应用:IP、IPX、APPLETALK、ICMP;
数据链路层:
1.主要功能:保证无差错的疏忽链路的data link;
2.典型设备:交换机、网桥、网卡;
3.典型协议、标准和应用:802.2、802.3ATM、HDLC、FRAME RELAY;
物理层:
1.主要功能:传输比特流Physical;
2.典型设备:集线器、中继器
3.典型协议、标准和应用:V.35、EIA/TIA-232.
http协议 对应于应用层
tcp协议 对应于传输层
ip协议 对应于网络层
三者本质上没有可比性。 何况HTTP协议是基于TCP连接的。
TCP(Transmission Control Protocol,传输控制协议)是面向连接的协议,也就是说,在收发数据前,必须和对方建立可靠的连接。
UDP(User Data Protocol,用户数据报协议)
(1) UDP是一个非连接的协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
(2) 由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。
(3) UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。
(4) 吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。
(5)UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的链接状态表(这里面有许多参数)。
(6)UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。
我们在传输数据时,可以只使用传输层(TCP/IP),但是那样的话,由于没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用应用层 协议,应用层协议很多,有HTTP、FTP、TELNET等等,也可以自己定义应用层协议。WEB使用HTTP作传输层协议,以封装HTTP文本信息,然 后使用TCP/IP做传输层协议将它发送到网络上。Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
3.1.套接字(Socket)概念
套接字(Socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应 用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。
3.2.建立Socket连接
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。
套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户 端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
3.3.Socket连接,TCP连接
创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。
3.4.Socket连接,Http连接
由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网络应用 中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。
而Http连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。
下载地址:https://github.com/robbiehanson/CocoaAsyncSocket
里面有GCDAsyncSocket(TCP)和GCDAsyncUdpSocket(UDP)
例:服务端在Windows电脑上找个第三方工具
//ViewController.m文件
// // ViewController.m // SockerLearn // // Created by Vie on 2017/2/9. // Copyright © 2017年 Vie. All rights reserved. // #import "ViewController.h" #import "GCDAsyncSocket.h" @interface ViewController ()<GCDAsyncSocketDelegate> @property(nonatomic,strong) GCDAsyncSocket *socket; @end @implementation ViewController -(GCDAsyncSocket *)socket{ if (!_socket) { //创建一个socket对象,代理方法都会在子线程调用,在刷新UI时就要回到主线程 _socket=[[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)]; _socket.IPv4PreferredOverIPv6 = NO; // 设置支持IPV6 } return _socket; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. float heightBtn=50; float widthBtn=self.view.frame.size.width*0.8; float btnX=(self.view.frame.size.width-widthBtn)/2; //连接服务器按钮 UIButton *connectBtn=[[UIButton alloc] initWithFrame:CGRectMake(btnX, 100, widthBtn, heightBtn)]; [connectBtn setTitle:@"连接服务器" forState:UIControlStateNormal]; [connectBtn setBackgroundColor:[UIColor colorWithRed:104/255.0 green:200/255.0 blue:250/255.0 alpha:1]]; [connectBtn.layer setCornerRadius:8.0f]; [connectBtn addTarget:self action:@selector(connectAction:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:connectBtn]; //登陆按钮(登陆其实就是发送消息校验) UIButton *loginBtn=[[UIButton alloc] initWithFrame:CGRectMake(btnX, 180, widthBtn, heightBtn)]; [loginBtn setTitle:@"登陆验证" forState:UIControlStateNormal]; [loginBtn setBackgroundColor:[UIColor colorWithRed:104/255.0 green:200/255.0 blue:250/255.0 alpha:1]]; [loginBtn.layer setCornerRadius:8.0f]; [loginBtn addTarget:self action:@selector(loginAction:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:loginBtn]; //断开连接 UIButton *closeBtn=[[UIButton alloc] initWithFrame:CGRectMake(btnX, 260, widthBtn, heightBtn)]; [closeBtn setTitle:@"断开连接" forState:UIControlStateNormal]; [closeBtn setBackgroundColor:[UIColor colorWithRed:104/255.0 green:200/255.0 blue:250/255.0 alpha:1]]; [closeBtn.layer setCornerRadius:8.0f]; [closeBtn addTarget:self action:@selector(closeAction:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:closeBtn]; } //连接Socket服务 -(void)connectAction:(UIButton *)sender{ NSLog(@"连接Socket服务器"); NSString *host=@"192.168.191.1"; int port=5678; //连接服务器 NSError *error=nil; // [self.socket connectToHost:host onPort:port error:&error]; //设置连接超时时间 [self.socket connectToHost:host onPort:port withTimeout:15 error:&error]; if (error) { NSLog(@"%@",error); } } //发送消息Socket登陆验证 -(void)loginAction:(UIButton *)sender{ NSLog(@"发送消息Socket登陆验证"); //登陆指令(本质是发送消息接收消息) NSString *loginInfo=@"Vie:123456 "; NSData *data=[loginInfo dataUsingEncoding:NSUTF8StringEncoding]; //-1不设置超时 [self.socket writeData:data withTimeout:-1 tag:0]; } //断开Socket连接 -(void)closeAction:(UIButton *)sender{ NSLog(@"断开Socket连接"); [self.socket disconnect]; } #pragma mark GCDAsyncSocketDelegate数据发送成功执行回调 -(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{ NSLog(@"数据成功发送到服务器"); //自己调用下读取数据的方法,接着Socket才会执行didReadData(每当你接收到数据之后,需要再次设置) [self.socket readDataWithTimeout:-1 tag:tag]; } #pragma mark GCDAsyncSocketDelegate接收到数据 -(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ //将接收到的数据转换成字符串,中文编码要一致 NSString *responseString=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"收到数据tag:%ld 内容:%@",tag,responseString); //每次读完数据后,都要调用一次监听数据的方法Socket才会执行didReadData [self.socket readDataWithTimeout:-1 tag:tag]; } #pragma mark GCDAsyncSocketDelegate连接服务器结果回调 -(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{ NSLog(@"连接主机成功"); } -(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{ if (err) { NSLog(@"连接失败"); }else{ NSLog(@"正常断开"); } } @end