【Linux】网络基础概念(下)

📅 2026/7/16 3:59:46
【Linux】网络基础概念(下)
目录一、Socket编程基础1.1 理解源IP地址和目的IP地址1.2 认识端口号pid vs portip vs port理解socket1.3 传输层的典型代表1.4 网络字节序1.5 Socket通用结构体个人主页矢望个人专栏C、Linux系统编程、Linux网络编程、C语言、数据结构、Coze-AI、MySQL一、Socket编程基础1.1 理解源IP地址和目的IP地址主机A和主机B在通信通过将数据从主机A发送到主机B的手段可以达到让用户通信的目的源IP和目的IP保证了主机之间进行通信。进程是用户在系统中的代表只要把数据给进程用户就相当于就拿到了数据。所以数据传输到主机不是目的而是手段。到达主机内部在交给主机内的进程才是目的。但是系统中同时会存在非常多的进程当数据到达目标主机之后怎么转发给目标进程这就需要在网络的背景下在系统中标识进程的唯一性。1.2 认识端口号端口号(port)是传输层协议的内容。端口号是一个2字节16位的整数端口号用来标识一个进程告诉操作系统当前的这个数据要交给哪一个进程来处理IP地址端口号能够标识网络上的某一台主机的某一个进程一个端口号只能被一个进程占用。以主机A某一进程向主机B某一进程发消息为例主机B会从网络中收到相关的报文这个报文中会标出它的源IP地址是谁目的IP地址是谁源端口号是谁目的端口号是谁通过目的IP地址找到了主机B到时候还会通过目的端口号找到主机B上的特定进程比如两台主机通过各自的QQ进程聊天QQ绑定的端口号就是固定的。所以网络通信的本质是两个进程之间在通信也就是进程间通信。在冯诺依曼体系的视角下看待网络通信就是IO你上网无非两件事上传数据、下载数据在Linux视角下一切皆文件网络也是文件所以本质也是IO。端口号范围划分•0 - 1023知名端口号HTTP, FTP, SSH等这些广泛使用的应用层协议它们的端口号都是固定的。•1024 - 65535操作系统动态分配的端口号。客户端程序的端口号就是由操作系统从这个范围分配的。pid vs portpid不就可以标志进程的唯一性了吗为什么还要有端口号首先pid是系统的概念在网络中还使用pid的话会造成强耦合所以第一个原因使用端口号port来标识本身就是一种解耦工作。pid每个进程都要有但是不是所有的进程都要进行网络通信所以不是所有进程都需要端口号这个时候有端口号的进程肯定就进行了网络通信。端口号起到了强标识的作用。ip vs portip标识公网中的唯一一台主机端口号标识主机中的唯一一个进程。OS是如何把收到的数据转发给特定端口的进程的在操作系统中有很多的哈希列表其中就有存储端口号到进程映射的列表操作系统通过提取报文的报头就可以提取出该报文要发的端口号于是就根据端口号映射到进程。找到进程之后如何把网络数据交给这个进程操作系统中有很多的报文所以就需要使用数据结构对这些报文做管理可以是链表等。在操作系统通过端口号找到进程之后就可以找到进程的文件描述符fd就可以找到进程的缓冲区这样就可以将网络数据拷贝给进程。理解socket综上IP地址用来标识互联网中唯一的一台主机port用来标识该主机上唯一的一个网络进程。所以IPPort就能标识互联网中唯一的一个进程。我们把ipport叫做套接字socket。(socket的汉语意思是插座)1.3 传输层的典型代表如上图传输层和网络层是在操作系统内核中的应用层想要访问内核必须通过系统调用所以应用层想要访问网络功能必须通过系统调用。认识TCP协议TCP(Transmission Control Protocol)是传输控制协议它为应用程序提供稳定的端到端数据传输服务。有这些特点传输层协议有连接可靠传输面向字节流。认识UDP协议UDPUser Datagram Protocol)是用户数据报协议适合对实时性要求高、允许少量丢包的应用。有这些特点传输层协议无连接不可靠传输面向数据报。有无连接这两种协议在设计的时候是要满足通信时的所有场景和需求的日常通信无非就是有连接和无连接例如打电话就是有连接它需要保证双方都接通例如发微信发邮件就是无连接一方发送数据即可。可靠不可靠并不是TCP或UDP的优缺点而是这两种协议的特点要保证可靠就意味着需要做其它更多的维护工作更复杂。而不可靠就意味着这个协议更轻量化。优缺点是伴生出现的。TCP的应用场景例如支付场景必须保证可靠。UDP的应用场景例如直播实时性较高如果使用TCP维护成本大。TCP和UDP在日常的使用比例大概8:2。1.4 网络字节序内存中的多字节数据相对于内存地址有大端和小端之分磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分网络数据流同样有大端小端之分。如上图将低权值位数据存放在低地址处叫做小端存储将高权值位数据存放在低地址处叫做大端存储。也就是小小小小权值位数据存放在小地址处就是小端存储。网络数据流发送这样规定先发送低地址处的数据再发送高地址处的数据。当一个主机是大端存储而另一个主机是小端存储并且大端主机向小端发送数据时大端存储的主机存储0x11223344后发送给小端存储的主机此时小端存储主机的低地址处收到的是11这样小端存储的主机读出的数据就成了0x44332211。为了避免这种情况TCP/IP协议规定网络数据流应采用大端字节序即低地址高字节。也就是所有发送到网络上的数据都必须是大端的选择大端存储可能是因为人读数据习惯从低向高读例如1234我们会先读权值高的1大端存储的情况下高权值位的数据刚好在低地址处。为使网络程序具有可移植性使同样的C代码在大端和小端计算机上编译后都能正常运行可以调用以下库函数做网络字节序和主机字节序的转换。h表示hostn表示networkl表示32位长整数s表示16位短整数。例如htonl表示将32位的长整数从主机字节序转换为网络字节序例如将IP地址转换后准备发送。如果主机是小端字节序这些函数将参数做相应的大小端转换然后返回如果主机是大端字节序这些函数不做转换将参数原封不动地返回。1.5 Socket通用结构体socket常见API// 创建 socket 文件描述符 (TCP/UDP, 客户端 服务器)intsocket(intdomain,inttype,intprotocol);// 绑定端口号 (TCP/UDP, 服务器)intbind(intsocket,conststructsockaddr*address,socklen_t address_len);// 开始监听socket (TCP, 服务器)intlisten(intsocket,intbacklog);// 接收请求 (TCP, 服务器)intaccept(intsocket,structsockaddr*address,socklen_t*address_len);// 建立连接 (TCP, 客户端)intconnect(intsockfd,conststructsockaddr*addr,socklen_t addrlen);在上面的API中sockaddr结构体出现的频率很高。Socket网络通信它也支持本地通信所以为了支持多种通信方式它就有多种socket例如网络通信套接字INET socket本地通信unix域间socket还有原始套接字raw socket。结构越复杂记忆和学习成本越高对新技术的传播也不利socket设计者考虑到了这一点并通过统一的一套API接口解决了这一点并引入了一个结构体sockaddr来保证API传递参数的一致。如上图网络通信本地通信和sockaddr结构体都拥有一个16位地址类型的部分将来在调用函数例如int bind(int socket, const struct sockaddr *address, socklen_t address_len);时可以先定义对象比如struct sockaddr_in addr;addr.xxx ip;等然后标注清楚自己是什么地址类型addr.地址类型 AF_INET;紧接着调用函数的时候就将这个结构体变量强转成struct sockaddr*类型由于sockaddr结构体中也有16位地址类型所以它就可以通过判断是AF_INET或者是AF_UNIX来强转成相关结构体的指针这样就可以进行访问了。也就是基类指针指向子类对象就是使用C语言实现了多态如上图几种不同的socket它们使用的都是同一套接口这样就减少了记忆和学习的成本。并且基类sockaddr还保证了接口采用统一的参数传递。总结以上就是本期博客分享的全部内容啦如果觉得文章还不错的话可以三连支持一下你的支持就是我前进最大的动力技术的探索永无止境! 道阻且长行则将至后续我会给大家带来更多优质博客内容欢迎关注我的CSDN账号我们一同成长(▽)