iOS 网络通信原理和socke通信原理/OSI七层模型

66 篇文章 4 订阅

OSI七层网络模型:


1.物理层:二进制转换成电流,电流转换成二进制,中继器放大电信号, 最小传输单位-----位(比特流),定义物流设备标准,如网线接口类型,传输介质速率.

2.数据链路层:对比特流的包装,检测保证数据传输的可靠性,对mac地址的解封装,交换机处在者一层,最小传输单位----帧.

MAC(Media Access Control或者Medium Access Control)地址,意译为媒体访问控制,或称为物理地址、硬件地址,用来定义网络设备的位置。OSI模型中,第三层网络层负责 IP地址,第二层数据链路层则负责 MAC地址。因此一个主机会有一个MAC地址,而每个网络位置会有一个专属于它的IP地址。MAC地址是网卡决定的,是固定的。用来表示互联网上每一个站点的标识符,采用十六进制数表示,共六个字节(48位)。其中,前三个字节是由IEEE的注册管理机构RA负责给不同厂家分配的代码(高位24位),也称为“编制上唯一的标识符”(Organizationally Unique Identifier),后三个字节(低位24位)由各厂家自行指派给生产的适配器接口,称为扩展标识符(唯一性)。一个地址块可以生成224个不同的地址。MAC地址实际上就是适配器地址或适配器标识符EUI-48。

MAC(Media Access Control, 介质访问控制)地址,也叫硬件地址,长度是48比特(6 字节),由16进制的数字组成,分为前24位和后24位:
  • 前24位叫做组织唯一标志符(Organizationally Unique Identifier,即OUI),是由IEEE的注册管理机构给不同厂家分配的代码,区分了不同的厂家。
  • 后24位是由厂家自己分配的,称为扩展标识符。同一个厂家生产的网卡中MAC地址后24位是不同的。
MAC地址对应于OSI参考模型的第二层数据链路层,工作在数据链路层的交换机维护着计算机MAC地址和自身端口的数据库,交换机根据收到的数据帧中的“目的MAC地址”字段来转发数据帧。
IP地址工作在OSI参考模型的第三层网络层。两者之间分工明确,默契合作,完成通信过程。IP地址专注于网络层,将数据包从一个网络转发到另外一个网络;而MAC地址专注于数据链路层,将一个数据帧从一个节点传送到相同链路的另一个节点。
在一个稳定的网络中,IP地址和MAC地址是成对出现的。如果一台计算机要和网络中另一外计算机通信,那么要配置这两台计算机的IP地址,MAC地址是网卡出厂时设定的,这样配置的 IP地址就和MAC地址形成了一种对应关 系。在数据通信时,IP地址负责表示计算机的网络层地址,网络层设备(如路由器)根据IP地址来进行操作;MAC地址负责表示计算机的数据链路层地址,数据链路层设备(如交换机)根据MAC地址来进行操作。IP和MAC地址这种映射关系由ARP(Address Resolution Protocol, 地址解析协议 )协议完成。




3.网络层:位于地理位置不同的网络中的两个主机系统之间提供链接和路径选择,路由器在这一层,寻找iP地址,最小单位----分组(包);这一层会有网络阻塞(处理数据需要时间,耽误这些时间,其他数据需要等待产生阻塞);

网关:网间连接器,协议转换器,网关在网络层上实现网络互连,对接收到的信心重新打包,以适应目的系统的需求;

网关实质上是一个网络通向其他网络的IP地址;只有通过网关才能找到对应的IP,只有设置好网关的IP地址,TCP/IP协议才能实现不同网络之间的相互通信,网关的IP地址是具有路由功能的设备的IP地址,具有路由功能的设备有路由器、启用了路由协议的服务器(实质上相当于一台路由器)、代理服务器(也相当于一台路由器)。



  解决阻塞的办法:数据分组,编号传输出去;然后接收到数据后排序重组解码;选择最优路径;丢包也是发生在网络层.

4.传输层:定义传输数据的协议和端口号(TCP/IP参考模型),每个服务占一个端口号;tcp三次握手建立数据传输通道;通道两端都会有socket;

5.会话层:数据的收发;最小单位---spdu;

6.表示层:确保一个系统的应用层发送的消息可以被另一个系统的应用层读取,编码转换,数据解析;  最小单位----ppdu;

7.应用层:为操作系统或网络应用程序提供访问网络服务的接口,应用层协议包括:telnet(Internet远程登录服务的标准协议和主要方式),FTP(文件传输协议),http(超文本传输协议),snmp简单网络管理协议,DNS;最小单位---apdu;

应用层为操作系统或网络应用程序提供访问网络服务的接口。

 

应用层协议的代表包括:

Telnet

Internet

远程登录服务的标准

协议和主要方式)、

FTP

(文件传输协议)、

HTTP

(超文本传送协

议)、

SNMP

(简单网络管理协议)等。


8.socket俗称套接字,本人理解为通信的两端,应用程序通过socket向网络发送请求或向网络做出应答,网路通信的实质就是数据在两个socket之间通过输入输出流传输数据,是socket位于 传输层和应用层之间;



网络参考模型



消息发送





iP和端口




TCP和UDP


TCP的三次握手:

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接。

客户端在收发数据前要使用 connect() 函数和服务器建立连接。建立连接的目的是保证IP地址、端口、物理链路等正确无误,为数据的传输开辟通道。

TCP建立连接时要传输三个数据包,俗称 三次握手(Three-way Handshaking)。可以形象的比喻为下面的对话:
  • [Shake 1] 套接字A:“你好,套接字B,我这里有数据要传送给你,建立连接吧。”
  • [Shake 2] 套接字B:“好的,我这边已准备就绪。”
  • [Shake 3] 套接字A:“谢谢你受理我的请求。”

TCP数据报结构

我们先来看一下TCP数据报的结构:


带阴影的几个字段需要重点说明一下:
1) 序号:Seq(Sequence Number)序号占32位,用来标识从计算机A发送到计算机B的数据包的序号,计算机发送数据时对此进行标记。

2) 确认号:Ack(Acknowledge Number)确认号占32位,客户端和服务器端都可以发送,Ack = Seq + 1。

3) 标志位:每个标志位占用1Bit,共有6个,分别为 URG、ACK、PSH、RST、SYN、FIN,具体含义如下:
  • URG:紧急指针(urgent pointer)有效。
  • ACK:确认序号有效。
  • PSH:接收方应该尽快将这个报文交给应用层。
  • RST:重置连接。
  • SYN:建立一个新连接。
  • FIN:断开一个连接。
对英文字母缩写的总结:Seq 是 Sequence 的缩写,表示序列;Ack(ACK) 是 Acknowledge 的缩写,表示确认;SYN 是 Synchronous 的缩写,愿意是“同步的”,这里表示建立同步连接;FIN 是 Finish 的缩写,表示完成。

连接的建立(三次握手)

使用 connect() 建立连接时,客户端和服务器端会相互发送三个数据包,请看下图:


客户端调用 socket() 函数创建套接字后,因为没有建立连接,所以套接字处于 CLOSED状态;服务器端调用 listen() 函数后,套接字进入 LISTEN状态,开始监听客户端请求。

这个时候,客户端开始发起请求:
1) 当客户端调用 connect() 函数后,TCP协议会组建一个数据包,并设置 SYN 标志位,表示该数据包是用来建立同步连接的。同时生成一个随机数字 1000,填充“序号(Seq)”字段,表示该数据包的序号。完成这些工作,开始向服务器端发送数据包,客户端就进入了 SYN-SEND状态。

2) 服务器端收到数据包,检测到已经设置了 SYN 标志位,就知道这是客户端发来的建立连接的“请求包”。服务器端也会组建一个数据包,并设置 SYN 和 ACK 标志位,SYN 表示该数据包用来建立连接,ACK 用来确认收到了刚才客户端发送的数据包。

服务器生成一个随机数 2000,填充“序号(Seq)”字段。2000 和客户端数据包没有关系。

服务器将客户端数据包序号(1000)加1,得到1001,并用这个数字填充“确认号(Ack)”字段。

服务器将数据包发出,进入 SYN-RECV状态。

3) 客户端收到数据包,检测到已经设置了 SYN 和 ACK 标志位,就知道这是服务器发来的“确认包”。客户端会检测“确认号(Ack)”字段,看它的值是否为 1000+1,如果是就说明连接建立成功。

接下来,客户端会继续组建数据包,并设置 ACK 标志位,表示客户端正确接收了服务器发来的“确认包”。同时,将刚才服务器发来的数据包序号(2000)加1,得到 2001,并用这个数字来填充“确认号(Ack)”字段。

客户端将数据包发出,进入 ESTABLISED状态,表示连接已经成功建立。

4) 服务器端收到数据包,检测到已经设置了 ACK 标志位,就知道这是客户端发来的“确认包”。服务器会检测“确认号(Ack)”字段,看它的值是否为 2000+1,如果是就说明连接建立成功,服务器进入 ESTABLISED状态。

至此,客户端和服务器都进入了 ESTABLISED状态,连接建立成功,接下来就可以收发数据了。

最后的说明

三次握手的关键是要确认对方收到了自己的数据包,这个目标就是通过“确认号(Ack)”字段实现的。计算机会记录下自己发送的数据包序号 Seq,待收到对方的数据包后,检测“确认号(Ack)”字段,看 Ack = Seq + 1是否成立,如果成立说明对方正确收到了自己的数据包。

socket通信图



========================

socket是纯c语言的,是跨平台的.


socket一般通信步骤

//1.创建socket

    /*

     int socket(int domain, int type, int protocol);

     1.协议族 ipv4或者其他的ip协议.

     2.type 指定传输层使用TCP或者 UDP (TCP SOCK_STREAM) (UDP SOCK_DGRAM数据报文)

     3.protocol指定传输层使用的协议

     返回值 大于0 创建socket成功

     */

    int clientSocket =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

    NSLog(@"%d",clientSocket);

    

    //2.建立连接

    /*

     1.socket

     2.const struct sockaddr * 指定对方服务器的ip地址和端口号等信息结构体

     struct sockaddr_in addr;

     addr.sin_family = AF_INET;

     addr.sin_port=htons(PORT);

     addr.sin_addr.s_addr = inet_addr(SERVER_IP);

     sockaddr_in sockaddr更加容易看的明白,可以类型转换

     3.结构体的字节长度

     

     返回值: 0 成功 0 失败

     */

    struct sockaddr_in addr;

    //指定协议族 ipv4

    addr.sin_family = AF_INET;

    //端口号,htons高地位转换

    addr.sin_port = htons(12345);

    //12345-->0x3039-->0x3930-->14640

//    NSLog(@"%d",htons(12345));

    //指定IP地址,inet_addr把字符串转换成网络地址(数字)

    addr.sin_addr.s_addr =inet_addr("127.0.0.1");

    

   int connResult = connect(clientSocket, (const struct sockaddr *)&addr, sizeof(addr));

    

    //本地开启服务器终端 (netcat)  nc -lk 12345

    if(connResult == 0){

        NSLog(@"ok");

    }else{

        NSLog(@"fail");

    }

    

    //3.发送数据给服务器

    /*

     1.socket

     2.要发送的数据

     3.要发送数据的字节长度

     4.调用执行方式 flag是否阻塞,一般填0即可

     返回值:成功发送的字节数

     */

    

    char * str = "itcast";

    ssize_t sentLen = send(clientSocket, str, strlen(str), 0);

    //sizeof表示在内存中保存该变量需要多少字节 ,一个字节8

//    NSLog(@"%zd %lu %lu",sentLen,strlen(str),sizeof(str));

    

    //4.接受数据(从服务器接收数据)

    /*

     1.socket

     2.用于保存数据的缓存

     3.缓冲区的长度

     4.指定调用方式。一般填0即可

     返回值接收的字节长度

     */

    char *buffer[1024];

    ssize_t recvLen = recv(clientSocket, buffer, sizeof(buffer),0);

//    NSLog(@"---->%zd",recvLen);

    

    //输出字符串

    //二进制 NSData

    NSData *data = [NSDatadataWithBytes:bufferlength:recvLen];

    //字符串输出

    NSString *string = [[NSStringalloc]initWithData:dataencoding:NSUTF8StringEncoding];

    

    NSLog(@"%@",string);

    

    //5.关闭数据

    //socket

    close(clientSocket);

===========================================
通过socket连接到百度

/*

 1.考代码

 2.连接到百度服务器

 3.发送http请求

 4.得到完整的响应

 ----截取响应体

 5.显示到界面

 */


#import "ViewController.h"

#import <sys/socket.h>

#import <netinet/in.h>

#import <arpa/inet.h>


@interface ViewController ()

@property (weak, nonatomic) IBOutletUIWebView *webview;


@property(nonatomic,assign)int clientSocket;


@end


@implementation ViewController


- (void)viewDidLoad {

    [superviewDidLoad];

    

    //2.连接到百度服务器治理不是填域名,ip地址 ping www.baidu.com

    //119.75.217.109  80

    BOOL connResult = [selfcreateAndConnWithIPaddress:@"119.75.217.109"port:80];

    if(connResult){

//        NSLog(@"ok");

    }else{

//        NSLog(@"fail");

    }

    

    //3.发送http请求,监控浏览器发出的请求

    //拼接请求

    NSString *requestString = @"GET / HTTP/1.1\r\n"

    "Host: www.baidu.com\r\n"

    "User-Agent: Android\r\n"

    "Connection: close\r\n\r\n";

    //keep-alive close

    /*

     Connection : keep-alive 长连接,等一段时间没有请求,释放连接.

     Connection : close 短连接 每次得到响应就释放连接.

     */

    

    //返回完整的响应,包含状态行,响应头,响应体

   NSString *responseString = [selfsendAndRecv:requestString];

    //截取响应体,截取依据空行

    NSRange range = [responseString rangeOfString:@"\r\n\r\n"];

    

    NSString *responseString2 = [responseStringsubstringFromIndex:range.location+range.length];

    

    NSLog(@"%@",responseString2);

    

    [self.webviewloadHTMLString:responseString2baseURL:[NSURLURLWithString:@"http://www.baidu.com"]];

}


//创建socket并连接服务器

-(BOOL)createAndConnWithIPaddress:(NSString *)ipaddress port:(int)port{

    

    self.clientSocket =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

    

    struct sockaddr_in addr;

    

    addr.sin_family = AF_INET;

    

    addr.sin_port = htons(port);

    

    addr.sin_addr.s_addr =inet_addr(ipaddress.UTF8String);

    

    int connResult = connect(self.clientSocket, (conststructsockaddr *)&addr,sizeof(addr));

    

    if(connResult == 0){

        

        return YES;

    }else{

        

        return NO;

    }

}


//发送数据并接受服务器返回的数据

-(NSString *)sendAndRecv:(NSString *)message{

    char * str = message.UTF8String;

    ssize_t sentLen = send(self.clientSocket, str,strlen(str),0);

    

    //大集合,用户组装每次接受的数据

    NSMutableData *mData = [NSMutableDatadata];

    char *buffer[1024];

    ssize_t recvLen = recv(self.clientSocket, buffer,sizeof(buffer),0);

    [mData appendBytes:buffer length:recvLen];

    while (recvLen != 0) {

        //不断的去取数据

        recvLen = recv(self.clientSocket, buffer,sizeof(buffer),0);

        [mData appendBytes:buffer length:recvLen];

    }

    

    //字符串输出

    NSString *string = [[NSStringalloc]initWithData:mData.copyencoding:NSUTF8StringEncoding];


    return string;

}




@end


================================
socket模拟聊天

/*

 1.界面搭建

 2.考代码

 ---创建socket并连接服务器

 ---发送

 */


#import "ViewController.h"

#import <sys/socket.h>

#import <netinet/in.h>

#import <arpa/inet.h>


@interface ViewController ()

@property (weak, nonatomic) IBOutletUITextField *tf_ipaddress;

@property (weak, nonatomic) IBOutletUITextField *tf_port;

@property (weak, nonatomic) IBOutletUITextField *tf_message;

@property (weak, nonatomic) IBOutletUITextView *tv_showMessage;


@property(nonatomic,assign)int clientSocket;


@end


@implementation ViewController

//发送

- (IBAction)sendClick:(id)sender {

    

    NSString *recvMsg = [selfsendAndRecv:self.tf_message.text];

    self.tv_showMessage.text = recvMsg;

    

}


//连接

- (IBAction)connClick:(id)sender {

    

    NSString *ipaddresss = self.tf_ipaddress.text;

    int port = [self.tf_port.textintValue];

    BOOL connResult = [selfcreateAndConnWithIPaddress:ipaddresssport:port];

    if(connResult){

        NSLog(@"ok");

    }else{

        NSLog(@"fail");

    }

}


//创建socket并连接服务器

-(BOOL)createAndConnWithIPaddress:(NSString *)ipaddress port:(int)port{

    

    self.clientSocket =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

    

    struct sockaddr_in addr;


    addr.sin_family = AF_INET;


    addr.sin_port = htons(port);


    addr.sin_addr.s_addr =inet_addr(ipaddress.UTF8String);

    

    int connResult = connect(self.clientSocket, (conststructsockaddr *)&addr,sizeof(addr));

    

    if(connResult == 0){


        return YES;

    }else{


        return NO;

    }

}


//发送数据并接受服务器返回的数据

-(NSString *)sendAndRecv:(NSString *)message{

    char * str = message.UTF8String;

    ssize_t sentLen = send(self.clientSocket, str,strlen(str),0);

    

    char *buffer[1024];

    ssize_t recvLen = recv(self.clientSocket, buffer,sizeof(buffer),0);

    

    NSData *data = [NSDatadataWithBytes:bufferlength:recvLen];

    //字符串输出

    NSString *string = [[NSStringalloc]initWithData:dataencoding:NSUTF8StringEncoding];

    

//    NSLog(@"%@",string);

    return string;

}


@end




  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值