从网络体系到TCP和UDP

网络结构

由于要通信的计算机存在差异性,所以会影响通信,需要在设计计 算机⽹络时要屏蔽掉这些差异性。

OSI体系结构

七层模型 ,亦称OSI(Open System Interconnection)。参考模型是国际标准化组织(ISO)制定的一个用于计算机或通信系统间互联的标准体系,一般称为OSI参考模型或七层模型。它是一个七层的、抽象的模型体,不仅包括一系列抽象的术语或概念,也包括具体的协议。

编号

层次

作用

7

应用层

为具体的应⽤提供⼀些协议,⾃定义

6

表示层

数据格式定义、数据转换/加密

5

会话层

建⽴通信进程的逻辑名字与物理名字的关联

4

传输层

差错控制/恢复、流量控制、提供可靠的传输

3

网络层

数据分组、路由选择

2

数据链路层

数据组成可发送、可接收的帧

1

物理层

传输物理信号(0、1)、接⼝、信号形式、速率

TCP/IP体系结构

TCP / IP模型是 协议模型

编号

层次

作用

4

应用层

为具体的应⽤提供⼀些协议,⾃定义

3

传输层

差错控制/恢复、流量控制、提供可靠的传输

2

网络层

数据分组、路由选择

1

网络接口层

数据组成可发送、可接收的帧

主机通信流程

以用户使用浏览器访问页面为例,你要访问百度查询信息,你的应用(浏览器)就知道你采用的是什么协议(http、https等),知道目标地址(ip、域名),请求内容。接下来有系统通过网络自动完成信息的发送。

物理层

物理层就是传输媒体介质,就是考虑的是怎么样才能在连接的计算 机的传输媒体上进⾏⽐特流的传输 。 物理层为数据链路层屏蔽了各种传输媒介的差异性,使数据链路层 只需要考虑如何完成本层的协议和服务,不⽤考虑传输介质问题 。

物理层协议:发送时,把0、1按照对应物理规定的⽅式物理信号发 送,接收时,根据规定在接收物理信号时转换成0、1。

数据链路层

据链路层在物理层提供的服务的基础上向网络层提供服务,其最基本的服务是将源自物理层来的 数据 可靠地 传输 到 相邻节点 的目标机网络层。 数据链路层定义了在单个链路上如何传输数据

链路:从⼀个结点到相邻结点的⼀段物理线路,中间没有经过其他 的交换结点

数据链路:是指把实现通信协议的硬件和软件加到链路上,就构成 了数据链路

:数据链路层以帧为单位传输和处理数据

数据链路层完成的功能

  • 封装成帧

  • 差错检测

  • 可靠传输

⽹络层

对于⽹络层的主要任务就是实现⽹络互联,从⽽实现数据包在各⽹ 络之间⽽传输。

主要要解决:

  • ⽹络层寻址问题

  • 路由选择问题

传输层(运输层)

通过⽹络层,实现了主机与主机之间的通信 。在实际⽹络中通信的真正实体是位于两个主机中的进程 。为运⾏在不同主机的应⽤进程提供通信是传输层的任务

传输 层协议也叫做端对端协议

TCP协议

UDP协议

两种协议⽤于不同形式的进程进⾏⽹络通信 使⽤传输层协议,可以在协议内容中填写要通信的双⽅进程是谁

UDP通信

1. ⽆连接,不需要提前把要通信的两个进程关联(连接)起来

2. ⾯向报⽂的传输,应⽤层的数据直接封装在UDP数据保报,既不拆分也不进⾏合并,直接交给⽹络层

3. 不可靠,尽最⼤努⼒到达,不保证数据安全,在使⽤UDP协议时,每次发送都要携带⽬标信息

UDP 常用于以下几个方面:

1.包总量较少的通信(DNS、SNMP等);

2.视频、音频等多媒体通信(即时通信);

3.限定于 LAN 等特定网络中的应用通信;

4.广播通信(广播、多播)。

UDP 报文格式

每个 UDP 报文分为 UDP 报头和 UDP 数据区两部分。报头由 4 个 16 位长(2 字节)字段组成,分别说明该报文的源端口、目的端口、报文长度和校验值。

  • 源端口:这个字段占据 UDP 报文头的前 16 位,通常包含发送数据报的应用程序所使用的 UDP 端口。接收端的应用程序利用这个字段的值作为发送响应的目的地址。这个字段是可选的,所以发送端的应用程序不一定会把自己的端口号写入该字段中。如果不写入端口号,则把这个字段设置为 0。这样,接收端的应用程序就不能发送响应了。

  • 目的端口:接收端计算机上 UDP 软件使用的端口,占据 16 位。

  • 长度:该字段占据 16 位,表示 UDP 数据报长度,包含 UDP 报文头和 UDP 数据长度。因为 UDP 报文头长度是 8 个字节,所以这个值最小为 8。

  • 校验值:该字段占据 16 位,可以检验数据在传输过程中是否被损坏。

udp⽹络通信

通信流程

函数

功能

作用

scoket()

创建套接字文件

有⽹络通信协议,能够完成两个应用程序之间的数据传输

bind()

指定(绑定)本地的⽹络信息

通信协议中需要有对应的信息

sendto()

recvfrom()

使⽤协议发送数据 使⽤协议接收数据

收发数据

close()

关闭套接字

断开连接

client
//用UDP协议向其他的主机发送数据
#include <arpa/inet.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <stdio.h>
 
int main()
 
    //1、创建套接字,在当前进程中有一个文件描述符代表一套通信协议
    int sockfd;
    sockfd = socket(AF_INET,SOCK_DGRAM,0);
 
    //2、绑定套接字(把本地网络信息绑定上套接字)
    struct sockaddr_in addr;//结构体变量存储本地信息
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8888);//端口port,发送端口
    addr.sin_addr.s_addr = inet_addr(locahost);//ip地址,32比特
 
    //3、发送数据
    struct sockaddr_in toaddr;//结构体变量存储接收方的信息
    toaddr.sin_family = AF_INET;
    toaddr.sin_port = htons(9999);//端口port,目标端口
    toaddr.sin_addr.s_addr = inet_addr(locahost);//ip地址,32比特
 
    char buf[50];
    while(1)
    {
        fgets(buf,50,stdin);//从终端输入数据到buf
        printf("%s",buf);
        
        if( sendto(sockfd,buf,50,0,(struct sockaddr *)&toaddr,sizeof(toaddr)) < 0)
        {
            printf("ok\n");
        }
    
    }
}
server
//用UDP协议接收数据
#include <arpa/inet.h>
#include <sys/types.h>        
#include <sys/socket.h>
#include <stdio.h>
 
int main()
{
 
    //1、创建套接字,在当前进程中有一个文件描述符代表一套通信协议
    int sockfd;
    sockfd = socket(AF_INET,SOCK_DGRAM,0);
 
    //2、绑定套接字(把本地网络信息绑定上套接字)  
    struct sockaddr_in addr;//结构体变量存储本地信息
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9999);//端口port,接收端的端口
    addr.sin_addr.s_addr = inet_addr(locahost);//ip地址,32比特
 
    bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));
 
    //3、接收数据
    struct sockaddr_in srcaddr;
    char buf[50];
    while(1)
    {
        //参数4:int flags:标志,0:阻塞接收
        //参数5:struct sockaddr *src_addr:结构体地址,表⽰存储源ip、port(发送⽅)的信息,如果不需要写NULL
        //参数6:socklen_t *addrlen:整数地址,表⽰存储结构体⼤⼩,不需要写NULL
        recvfrom(sockfd,buf,50,0,NULL,NULL);//
        printf("%s",buf);
 
    }  
}

TCP通信

1. TCP是⼀种可靠的传输服务(不会出现传输差错、丢失、 重复等各种现象)

2. 是⾯向连接的服务

3. ⼀个tcp连接只有两个端点,是⼀对⼀通信

4. 是可靠传输 ,拥塞控制、流量控制、超时重传

5. ⾯向字节流的传输⽅式

TCP通信流程

TCP是全双工的

TCP通信必须先建⽴连接,只有建⽴了连接之后TCP才能实现可靠传输。所以在进⾏TCP通信时,通信双⽅的操作会有部分区别,应该是⼀个主动去建⽴连接,另⼀个是等待连接请求,然后就建⽴连接进⾏通信,把主动的⼀端叫做客户端,把被动的⼀端叫做服务端(服务器端)

TCP是⼀种⾯向连接,在进⾏通信前连接是与个必不可少的过程,在通信完成后,断开连接也是必不可少的

TCP头

16位端口号

告知主机该报文段是来自哪里(源端口Source Port)以及传给哪个上层协议或应用程序(目标端口Destination Port)的。

进行TCP通信时,客户端通常使用系统自动选择的临时端口号,而服务器则使用知名服务端口号(比如DNS协议对应端口53,HTTP协议对应80,这些端口号可在/etc/services文件中找到)。

32位序号

一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。

32位确认号(acknowledgement number)

用作对另一方发送来的TCP报文段的响应。其值是收到的TCP报文段的序号值加1。、

4位头部长度(header length)

标识该TCP头部有多少个32bit字(4字节)。因为4位最大能标识15,所以TCP头部最长是60字节。

6位标志位

包含如下几项:

URG标志,表示紧急指针(urgent pointer)是否有效。

ACK标志,表示确认号是否有效。我们称携带ACK标识的TCP报文段为确认报文段。

PSH标志,提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间(如果应用程序不将接收到的数据读走,它们就会一直停留在TCP接收缓冲区中)。

RST标志,表示要求对方重新建立连接。我们称携带RST标志的TCP报文段为复位报文段。

SYN标志,表示请求建立一个连接。我们称携带SYN标志的TCP报文段为同步报文段。

FIN标志,表示通知对方本端要关闭连接了。我们称携带FIN标志的TCP报文段为结束报文段。

16位窗口大小(window size)

是TCP流量控制的一个手段。这里说的窗口,指的是接收通告窗口(Receiver Window,RWND)。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。

16位校验和(TCP check sum)

由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。注意,这个校验不仅包括TCP头部,也包括数据部分。这也是TCP可靠传输的一个重要保障。

16位紧急指针(urgent pointer)

是一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。因此,确切地说,这个字段是紧急指针相对当前序号的偏移,不妨称之为紧急偏移。TCP的紧急指针是发送端向接收端发送紧急数据的方法。

TCP头部选项

TCP头部的最后一个选项字段(options)是可变长的可选信息。这部分最多包含40字节,因为TCP头部最长是60字节(其中还包含前面讨论的20字节的固定部分)

tcp通信的三个阶段

1、建⽴连接 2、数据传输通信 3、释放连接

连接解决了以下问题: 1、使TCP通信双⽅都知道对⽅的存在 2、能够协商⼀些参数内容(如:最⼤窗⼝值、时间戳选项等) 3、能够使TCP双⽅对资源数据进⾏分配

TCP的三次握手

TCP建⽴连接:

建⽴tcp连接的步骤共有三步,叫做三次握⼿

第⼀次握⼿

TCP客户端打算建⽴连接,向服务器发送连接请求报⽂,客户端请 求建⽴连接,客户端进⼊同步发送状态(SYN-SEND) ,在请求报⽂中 把SYN = 1,表⽰这是⼀个请求连接报⽂ ,把序号字段seq = x(x就是⼀个初始值),作为客户端的初始序号 。

第⼆次握⼿

TCP服务器在受到客户端请求后,如果同意连接,则会向客户端发 送确认请求报⽂,服务器进⼊同步接收状态(SYN_RECV) ,在确认报⽂中 把同步位SYN和确认位ACK设置为1,表明这是⼀个请求确认报⽂ 把序号seq设置⼀个初始值y,作为服务器的初始序号 ,把确认号字段ack = x+1,作为对客户端的确认

第三次握⼿

TCP客户端在收到了服务器的确认信号后,还要向服务器发送⼀个 确认报⽂,并进⼊连接已建⽴(ESTABLISHED) ,发送针对服务器确认的确认报⽂ ,确认位ACK = 1,表⽰这是⼀个确认报⽂ ,序号seq = x+1,第⼀次是x,第⼆次发送x+1 ,确认号ack = y+1,这是对服务器的确认 ,服务器收到,进⼊连接已建⽴(ESTABLISHED)

TCP的四次挥手

TCP连接释放:释放连接(关闭)步骤共有四歩,叫做四次挥⼿

第一次挥手

tcp客户端通知主动关闭tcp连接,tcp客户端发送连接释放(断开)报 ⽂,并进⼊终⽌等待态1 状态 ,终⽌位FIN和确认位ACK设置为1,表⽰是⼀个tcp连接释放报⽂, 同时对之前的报⽂做确认 ,序号seq设置为u,等于之前已经传送过去的数据最后⼀个字节序号 +1 ,确认号ack设置为v,等于之前已经收到的数据最后⼀个字节序号 +1

第二次挥手

tcp服务器收到tcp连接断开请求报⽂,会发送⼀个确认报⽂给客户 端,并进⼊关闭等待状态,客户端收到确认会进⼊终⽌等待态2 状 态 ,确认号ACK设置为1,表明是⼀个确认报⽂ ,序号seq = v,就是之前服务器发送的最后⼀个字节+1,与第⼀次挥 ⼿客户端的确认号做匹配 ,确认号ack = u+1 ,继续把当前没有传输完成的数据传输完毕

第三次挥手

tcp服务端给客户端发送连接释放报⽂,并进⼊最后确认状态 ,终⽌位FIN个确认号ACK设置为1,表⽰这是⼀个tcp连接释放,同时 对之前的数据做确认 ,seq序号设置为w,这时服务器在半关闭状态 ,ack确认号设置为u+1,释放的重复确认

第四次挥手

tcp客户端收到连接释放,发送确认报⽂,进⼊时间等待状态 ,确认号ACK = 1,表⽰是⼀个确认报⽂ 序号seq = u+1,表⽰是⼀个释放报⽂ ,确认号ack = w+1,表⽰是⼀个确认

TCP网络通信

client
//这是tcp客户端,要与服务器进行通信(收发数据),客户端发送,服务器原样返回
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
 
//TCP客户端
int main()
{
 
 
    //1、创建套接字-------TCP通信
    int clientfd = socket(AF_INET,SOCK_STREAM,0);//tcp通信套接字
    if(clientfd < 0)
    {
        printf("error\n");
        return -1;
    }
 
    //2、绑定套接字------在TCP通信套接字上绑定本地网络信息(ip、port)
    //绑定自己的网络信息可以不写,由系统自动完成
    struct sockaddr_in clientaddr;//结构体变量,用于表示本地网络信息,需要加入到bind函数中使用
    clientaddr.sin_family = AF_INET;
    clientaddr.sin_port = htons(10000);
    clientaddr.sin_addr.s_addr = inet_addr(locahost);
 
    bind(clientfd,(struct sockaddr *)&clientaddr,sizeof(clientaddr));
 
    //3、请求服务器连接,客户端使用自己的套接字请求与对应的服务器建立连接
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(9999);
    serveraddr.sin_addr.s_addr = inet_addr(locahost);
    
    int ret;
    ret = connect(clientfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
    if(ret == 0)
    {
        printf("connect ok\n");
    }
    else
    {
        printf("connect error\n");
        return -1;
    }
 
    //4、通信
    char buf[20];
    while(1)
    {
        //先发送
        fgets(buf,20,stdin);
        send(clientfd,buf,20,0);
        //再接收
        recv(clientfd,buf,20,0);
        printf("client recv data is %s",buf);
    }
 
    close(clientfd);//把套接字关闭
 
    return 0;
 
}
server
//这是tcp服务端,用于和客户端进行通信,接收客户端数据后,直接把接收的数据返回
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
 
//tcp服务端
int main()
{
 
    //1、创建套接字
    int serverfd = socket(AF_INET,SOCK_STREAM,0);//按照ipv4、tcp创建的套接字
 
    //2、绑定套接字
    struct sockaddr_in serveraddr;//结构体变量,表示本地网络信息内容
    serveraddr.sin_family = AF_INET;//地址族
    serveraddr.sin_port = htons(9999);//端口port号
    serveraddr.sin_addr.s_addr = inet_addr(locahost);//ip地址    
 
    bind(serverfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
 
    //3、监听套接字,监听服务端自己的网络信息,查看有客户端来进行连接请求
    listen(serverfd,3);//等待队列大小3,自动进行监听
    printf("listen ok\n");
 
    //4、接收客户端连接请求
    int cfd1 = accept(serverfd,NULL,NULL);//如果有连接再accpet,没有就等待,cfd1就是与对应客户端进行通信的套接字
    printf("accept ok\n");
    
    //5、通信
    char buf[20];
    while(1)
    {
        recv(cfd1,buf,20,0);//接收客户端的数据
        printf("recv data is %s",buf);
        send(cfd1,buf,20,0);
    }
 
    close(cfd1);
    close(serverfd);
 
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值