微信公众号开发 Hibernate bash recursion stl stream uicollectionview jwt mono Font Awesome vue开发 pmp视频教程 git视频教程 广告投放系统源码 jquery解析json idea大小写转换快捷键 js获取月份 h5下拉刷新 bootstrap颜色 less的比较级 python随机函数 python中assert 安装python教程 python中不等于 javaswitch java实现接口 java查看版本 java集成 hadoop权威指南 渐变事件 fireworks8序列号 网络工程师教程 自动回复机器人 x64dbg hyqihei 发射爱心的图片 hzfs 脚本大师 键盘灯怎么关 无线中继是什么意思
当前位置: 首页 > 学习教程  > 编程语言

【Linux】网络基础,你一定能涨知识的文章!!

2020/12/28 18:43:53 文章标签:

文章目录一. 网络协议1.1 协议分层1.2 数据包封装与分用 (TPC/IP 五层模型)1.3 网络当中的两台计算机是如何进行通信的?(IP Port)1.4 IP协议的版本:二. 网络字节序与主机字节序2.1 前提2.2 字节序转换三. TCP协议与UDP协议3.1 UDP编程流程一. 网络协议 …

文章目录

  • 一. 网络协议
    • 1.1 协议分层
    • 1.2 数据包封装与分用 (TPC/IP 五层模型)
    • 1.3 网络当中的两台计算机是如何进行通信的?(IP + Port)
    • 1.4 IP协议的版本:
  • 二. 网络字节序与主机字节序
    • 2.1 前提
    • 2.2 字节序转换
  • 三. TCP协议与UDP协议
    • 3.1 UDP编程流程

一. 网络协议

前提:为什么需要网络协议?
计算机生产商很多,操作系统很多,网络硬件设备也有很多。因此为了使不同计算机能保证相互顺畅的通信,因此必须要一个共同的约定标准,这就是网络协议。

网络协议: 在网络当中,通信双方对数据交换和数据传输做出的约定
协议簇: 计算机当中有很多网络协议,将这些网络协议联系在一起就叫协议簇,(TCP/IP)
参考模型或者体系结构: 在协议簇当中,定义各个协议之间的相互关系和协议需要完成的任务

1.1 协议分层

OSI参考模型(七层模型): (只具有参考意义,实际上没有用到,因为分层太细)
分别是:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层

TCP/IP (五层模型):
物理层,数据链路层,网络层,传输层,应用层

  1. 应用层:负责应用层程序之间的数据传输,程序员就是工作在这一层面的,即代码在应用层
    典型的协议:HTTP协议,FTP协议,DNS协议,SMTP协议
  2. 传输层:负责端口和端口之间的数据传输
    典型协议:TCP协议和UDP协议
  3. 网络层:负责路由选择和地址管理
    典型协议:IP协议,ARP协议,ICMP协议
    典型设备:路由器
  4. 数据链路层:负责相邻设备之间的数据帧传输
    典型协议:以太网协议(Ethernet)
    典型设备:交换机
  5. 物理层:负责光电信号的传输
    典型协议:以太网协议
    典型设备:集线器

1.2 数据包封装与分用 (TPC/IP 五层模型)

在这里插入图片描述

封装: 应用层数据通过协议栈发送到网络上时,每层协议都要加上一个数据首部,首部信息中包含了一些上层协议信息。只有封装了地址信息,才能知道发送到哪一台主机的哪一个进程中去
分用: 数据到达目的主机之后,每层协议再剥离掉相应的首部。

1.3 网络当中的两台计算机是如何进行通信的?(IP + Port)

  1. IP地址:在网络当中唯一标识一台主机
    本质:unit32_t值,无符号4个字节,范围0~42亿
    192.168.113.192 --》点分十进制表示方法,以点分割,每个字节最大能表示的数是255
    例:192.168.256.113 --》非法IP地址
    源IP地址:当前这个数据从哪一个机器上面来的
    目的IP地址:当前这个数据要去往哪一个机器
  2. Port端口:在一台主机中标识一个进程
    本质:unit16_t,范围0~65536,无符号16位整数,一个端口只能被一个进程所占用,一个进程可以绑定多个端口
    端口:(0~1023),被知名协议所占用
    例:http协议:80、https协议:443、ssh协议:22、mysql:3306、oracle:1521
    我们在开发应用程序的时候,应该杜绝占用知名端口,因为一个端口只能被一个进程所占用
  3. 五元组信息:源IP + 源端口 + 目的ip + 目的端口 + protocol
    网络通信中,每一条数据都是需要具备5个信息,我们称之为5元组。
    1 源IP地址:src_ip,当前这个数据从哪一个机器上面来的
    2 目的IP地址:dest_ip,当前这个数据要去往哪一个机器
    3 源端口:src_port,从源主机上面哪一个进程来的,当回复应答的时候,知道回复到哪一个进程去
    4 目的端口:dest_port,去往哪一个主机上面的进程
    5 协议:protocol,标识使用什么协议

1.4 IP协议的版本:

ip协议分为两个版本:ipv4 和 ipv6,默认指ipv4

  1. ipv4:无符号32位–》4字节,(0~2^32)大概42亿 ,因此 ipv4 版本的IP地址是不够的,面临资源枯竭
  2. ipv6:无符号128位(0~2^128)–》16字节
  3. ipv6 并不向下兼容 ipv4,因为包头格式不同
  4. IP表示方法:点分十进制,例:192 . 168 . 0 . 38

注意:
1.对外提供服务的端口一般不要变化,否则要通知所有用户来改变端口
2.服务端口在提供服务时必须绑定自己的port。

面试题:
1.为什么不使用PID作为请求,在主机当中查找进程呢?
这是由于每次进程关闭或者重启会导致该次启动PID和下次不一样,这样就对用户访问造成了困扰。
2.如何解决ipv4版本的资源枯竭?
动态主机分配协议:DHCP,给联网的主机分配IP,断网就回收IP
NAT地址转换协议:根本上解决了枯竭问题

二. 网络字节序与主机字节序

2.1 前提

字节序:CPU对内存中数据的存取访问顺序
小端字节序:低权值位数据放在地址处
大端字节序:低权值位数据放在地址处,网络字节序:大端字节序
通常发送主机是将发送缓冲区的数据按内存地址从低到高的顺序发出。接收主机则是把从网络中接收到的字节,按内存地址低到高的顺序,保存到接收缓冲区中。

2.2 字节序转换

前提:为什么需要转换网络字节序?

  1. 绑定了IP和port等信息的数据在传输到对端过程中,中间网络链路是按大端字节序解析的。如果发送时不是大端,则无法发送到目的对端
  2. 数据是不需要转换成网络字节序的,因为大多计算机都是小端机器

接口:
IP调用:
uint32_t htonl(uint32_t hostlong):将32位主机字节序转换成网络字节序,大端机器调用该接口不会改变
uint32_t ntohl(uint32_t netlong):将32位网络字节序转换成主机字节序

端口调用:
uint16_t htons(uint16_t hostshort):将16位主机字节序转换成网络字节序
uint16_t htons(uint16_t hostshort):将16位网络字节序转换成主机字节序

htonl --> host to net long
htons --> host to net short

三. TCP协议与UDP协议

tcp协议:

  1. 面向连接:TCP通信双方在发送数据之前,需要完成三次握手并建立连接
  2. 可靠传输:保证TCP数据包一定能到达对端,原因:必须连接完成才能通信
  3. 面向字节流:TCP协议下数据可以随意的存取(不会刷新缓冲区),每一条数据之间是没有间隔的,这也是TCP粘包的根源

udp协议:

  1. 无连接:UDP通信双方知道对端地址( IP和port )就可以发送数据了
  2. 传输不可靠:在网络传输中,数据包可能丢失掉,不保证数据一定能到达对端。原因:无需建立连接,对端可能没有接受数据
  3. 面向数据报:UDP协议下发送的数据是整条交付的,接收之后会刷新缓冲区

3.1 UDP编程流程

在这里插入图片描述
UDP编程接口:

1.创建套接字

int socket(int domain,int type,int protocor);
	用例:sockfd = socket(AF_INET, SOCK_DGRAM, IPPORT_UDP);	//采用ipv4版本的UDP类型套接字
			   或者socket(AF_INET, SOCK_DGRAM, 0);
	domain:地址域,指定"网络层"(IP所在层)在使用什么协议						
		网络层:AF_INET:IPV4版本的ip协议
		       AF_INET6:IPV6版本的ip协议
	type:套接字类型,传输层:tcp/udp
		SOCK_STREAM:面向字节流套接字--》默认协议是TCP协议,不支持UDP协议
		SOCK_DGRAM:用户数据报套接字--》默认协议是UDP协议,不支持TCP协议
	protocol:指定套接字所使用的协议
		0:采用套接字的默认协议
		IPPROTO_TCP--6     TCP协议
		IPPROTO_UDP--17	  UDP协议
	返回值:返回套接字操作句柄,其实就是一个文件描述符,我们一般称之为套接字描述符

eg:ll /proc/pid/fd 查看文件描述符

2.绑定地址信息

int bind(int sockfd,const struct sockaddr* addr,socklen_t addrlen);
	用例:bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
	sockfd:套接字操作句柄
	addr:地址信息 ip+port
	addrlen:地址信息的长度

用法:

struct sockaddr_in addr;		//创建一个结构体
addr.sa_family = AF_INET;		//设置协议,ipv4
addr.sin_port = htons(port);	//转换为网络字节序,设置端口地址
addr.sin_addr.s_addr = inet_addr(ip.c_str());	
//把字符类型ip转换成指针类型,再进一步转换成uint32,并设置ip地址为网络字节序。

在这里插入图片描述
在这里插入图片描述

完整解释: bind接口在设计的时候为了通用各种协议,定义了一个结构体struct sockaddr;而在进行具体协议地址信息绑定的时候,填充不同的结构体,之后将结构体对象的地址,强转为sockaddr传给bind函数
socklen:地址信息的长度,防止有的协议的地址信息长度大于16个字节,所以传递地址信息长度,告诉bind函数,应该如何解析地址信息

3.发送数据

ssize_t sendto(int sockfd,const void* buf,size_t len,int flags,const struct sockaddr* dest_addr,socklen_t addrlen)
	sockfd:套接字的操作句柄
	buf:要发送的数据,可以发送结构体,也可以发送字符串
	len:数据长度
	flags:0 阻塞发送
	dest_addr:目标主机的地址信息,要将数据发送到哪里去
		struct sockaddr_in:包含目标主机的IP地址和端口号(port)
	addr_len:地址信息长度
	返回值:返回实际发送的字节数量

注意:(UDP没有发送缓冲区)这句话是错的,只不过UDP是整条数据发送,所以在发送缓冲区当中打上UDP协议报头之后就提交给网络层了

4.接收数据

ssize_t recvfrom(int sockfd,void* buf,size_t len,int flag,struct sockaddr* src_addr,socklen_t* addrlen);
	sockfd:套接字操作句柄
	buf:将数据接收到哪里?
	len:最大接收的字节数
	flag:0 阻塞接收
	src_addr:数据源主机的IP地址和端口(source_addr :源地址)
	addrlen:地址信息的长度(结构体的大小)

5.关闭套接字
close(int sockfd);

源码见:https://github.com/Yfan133/Linux/tree/master/network/udp

运行结果:
在这里插入图片描述
查看端口状态命令:netstat -anp | grep port
在这里插入图片描述
总结:

  1. socket文件描述符闪烁? 原因:使用了内核缓冲区(管道)
  2. 不推荐lient绑定信息的 ? 原因:一个端口只能被一个进程占用,如果运行多个client,绑定报错并返回。
  3. 为什么要地址域? 原因:内核根据地址域来对结构体中的空间进行解析
  4. perr_addr_len在接收之前初始化? 原因:不然内核不知道应该怎么去解析长度,于是默认给 sin_port 赋值65536

源码见:https://github.com/Yfan133/Linux/tree/master/network/udp


本文链接: http://www.dtmao.cc/news_show_550103.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?