赞
踩
在上一篇博客中,我们简单的介绍了一些Linux网络一些比较基本的概念。本篇博客我们将开始正式学习Linux网络套接字的内容,那么我们开始吧!
大家一定知道每一台主机都会存在一个ip地址,其实并不是这么简单,今天我们就来系统介绍一下。
IP协议有两个版本, IPv4和IPv6. 我们整个的课程, 凡是提到IP协议, 没有特殊说明的, 默认都是指IPv4。IPv6其实是针对IPv4地址不足提出的解决方案,目前世界上IPV6做的比较好的国家就是我们。
在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址,用来表示这个数据是从哪台主机发出来的,要发给哪一台主机。
每一台连入网路的设备都必须需要网卡,每一张网卡在出厂时都有一个唯一性的编号,这个标号就是MAC地址。MAC同样具有全网内唯一性,通常用于处于局域网中主机之间相互通信。
MAC地址长度为6个字节,48个比特位。一般用16进制加上冒号的形式来表示,例如:
08:00:27:33:fd:45。
在Linux下查看ip地址和MAC地址的命令为:
[user@VM-8-5-centos ~]$ ifconfig
在这张图片中,展示的是Linux系统下通过ifconfig
命令查看的网络配置信息,特别是关于以太网接口eth0
的详细配置。接下来,我们分析一下这些内容:
以太网接口eth0:
4163<UP,BROADCAST,RUNNING,MULTICAST>
表示该接口已启用(UP)、支持广播(BROADCAST)、正在运行(RUNNING)以及支持多播(MULTICAST)。mtu 1500
表示该接口的最大传输单元为1500字节,这是以太网的标准MTU值。inet 10.0.8.5 netmask 255.255.252.0
表示该接口的IPv4地址是10.0.8.5,子网掩码是255.255.252.0,用于确定IP地址的网络部分和主机部分。broadcast 10.0.11.25
是该网络中的广播地址,用于向同一子网内的所有设备发送数据包。inet6 fe80::5054:ff:fe35:3d28 prefixlen 64 scopeid 0x20<
表示该接口还配置了一个IPv6的链路本地地址,前缀长度为64位。注意这里文本被截断,但基本意思是明确的。ether 52:54:00:35:3d:28
是该接口的物理地址,也称为MAC地址,用于在链路层唯一标识网络接口。接收(RX)和发送(TX)统计:
环回接口(lo):
lo
是环回接口,用于本机内部通信。它也有自己的IPv4和IPv6地址(127.0.0.1和::1),以及相应的接收和发送统计。错误消息:
如图所示,跨网络数据进行传输时,需要路由器。所以路由器必须要同时连接两个甚至多个局域网。数据该往哪个方向传输由IP地址决定。但是数据在长距离传输的过程中会经过多个路由节点,相邻路由节点的选择由MAC地址决定。
IP(公网IP)地址决定网络中主机的唯一性。但是仅仅需要IP地址就可以实现数据的传输吗?
打开快手刷视频时,为什么视频资源可以准确的显示在快手APP页面,而不是出现在微信APP页面呢?
我们把数据从主机A传输到主机B是目的吗?真正通信的不是这两个机器,而是这两个机器上的应用(人)。但是有可能主机A上不止一个应用(进程),可能同时还会有其他的进程,例如快手打开的同时,微信也开着。那么用什么来标识客户端或者服务器主机进程的唯一性呢?端口号
为了更好的表示一台主机上,服务器进程或者客户端进程的唯一性,我们采用端口号来标识主机上的不同进程。端口号保证主机唯一性即可,即一台主机上一个端口号只能绑定一个进程,不同主机上的相同端口号绑定的进程可以不同。
公网IP地址(标识主机全网唯一性)+主机上的端口号=表示该进程在全网中的唯一性
所以,网络通信的本质就是进程间通信嘛!其中的临界资源就是网络。
通信是在做什么?通信不就是IO的过程嘛。所以,我们所有的网络行为只有两种:①从网络中接收数据②发送数据到网络中。
IP保证全网唯一,port保证本机唯一。一个进程可以绑定多个端口号。
进程已经有pid了,为什么还要有端口号呢?
①系统是系统,网络是网络。做到互相解耦。维护成本低
②一般都是客户端主动向服务器发送请求。需要客户端快速的找到服务器进程。决定了服务器的IP和端口不能随便改变。所以决定了不能使用轻易会改变的值。pid不太满足这个条件。
所以,客户端向服务器发送消息时,要不要把客户端的ip和端口号发给服务器呢?要,因为服务器还有将消息发回给客户端。这就决定了在发送数据时,一定会多发一部分数据——以协议的形式呈现。
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?
那么,如果需要转化的话,转化的过程需要谁来完成呢?需要程序员自己来完成转换工作。当然,操作系统也给我们提供了相应的接口,我们调用即可。
接下来,我们简单介绍一下这些接口
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。
例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。
如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;
如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。
IP+port就可以表示一台主机的进程在网络中的唯一性,其中IP+Port合起来被称为网络套接字。
接下里,我们先见一下关于网络套接字创建,绑定端口,使用的相关函数。
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,
socklen_t address_len);
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,
socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
套接字的种类其实是比较多的。有
由于有三套不同的套接字,所以按理来说,操作系统要设计三套不同的接口分别对应三套不同的套接字。但是这对使用者来说简直是灾难,使用者要同时掌握三套接口。所以,为了方便使用,操作系统进行了如下的设计:
我们发现:struct sockaddr_in和struct sockaddr_un的接口不同,这使用起来就很麻烦。所以操作系统就设计了struct sockaddr结构。在使用时,就必须进行强制类型转换。
写到这里,本篇博客的内容就结束了,我们下期博客再见!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。