《网络通信的基石:套接字(Socket)核心知识点与实操要点》—-《Hello Linux!》(22)

AI1天前发布 beixibaobao
2 0 0

文章目录

  • 前言
  • 端口号(port)
  • TCP协议和UDP协议初识
  • 网络字节序
  • 套接字(socket)编程
    • socket常见的系统调用接口

前言

在网络通信中,套接字(Socket)是连接应用层与传输层的核心桥梁,也是实现进程间跨网通信的关键技术。从端口号的进程标识、TCP与UDP协议的差异化特性,到网络字节序的转换规则,再到套接字编程的地址结构体与系统调用接口,每一个知识点都直接决定了网络程序的稳定性与可靠性。本文围绕Socket编程核心模块展开,先铺垫端口、协议、字节序等基础概念,再深入拆解套接字地址结构体的设计逻辑,逐一生动解析创建、绑定、收发数据等系统调用的用法与注意事项,同时补充地址转换函数、全双工通信等实用知识点,帮助读者构建完整的Socket编程知识体系,为后续开发TCP/UDP网络程序、理解网络通信底层逻辑筑牢基础。

端口号(port)

在网络通信的时候,其实是进程在发送对应的请求

–所以日常通信的本质就是进程间通信

端口号就是用来标识这个主机上的唯一的一个进程

端口号是一个16位的整数

一个进程可以绑定多个端口号 但是一个端口号只能绑定一个进程

端口号跟进程pid的对比:

1.具备通信能力的进程才有端口号

2.让系统和网络功能解耦

端口号无论对于client(客户端)还是server(服务端),都能唯一的标识该主机上的一个网络应用层的进程

客户端获取服务端的端口号的方法:

一般来说每一个服务的端口号都是众所周知的,一般客户端直接把服务器的端口号内置进去了

比如:HTTP服务用80端口

一个端口号只能被一个进程bind–客户端和服务端都是如此

不然的话绑定同一个端口号的进程不能同时运行

[0,1023]是系统内定的端口号(知名端口),一般都有固定的应用层协议去使用 –比如http用的是80号

1024记以上的才可以给普通应用程序使用 –也不全是普通应用程序,比如mysql端口号在这个区间

一些知名端口号:

ssh服务器, 使用22端口

ftp服务器, 使用21端口

telnet服务器, 使用23端口

http服务器, 使用80端口

https服务器, 使用443端口

查询知名端口号的话,可以打开/etc/services这个文件

引申:一些指令:

iostat:可以用于监控磁盘 I/O 性能和 CPU 使用率

netstat:可以查看网络状态

格式:netstat [选项]

选项:

n:拒绝显示别名,能显示数字的全部转化成数字

l:仅列出有在 Listen (监听) 的服务状态

p:显示建立相关链接的程序名

t :仅显示tcp相关选项

u :仅显示udp相关选项

a :显示所有选项,默认不显示LISTEN相关

这里的local address是本机的信息 foreign address是远程主机的信息

pidof

格式:pidof [进程名] 可以通过进程名查看进程id

TCP协议和UDP协议初识

TCP协议:

1.属于传输层协议 2.有连接 3.是可靠传输 4.面向字节流

TCP会通过三次握手来进行链接的建立;通过四次挥手,进行链接的释放

UDP协议:

1.属于传输层协议 2.无连接 3.是不可靠传输 4.面向数据报

这个不可靠传输的意思就是:数据发没发成功不确定

面向数据报就是以数据报作为传输单元

网络字节序

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节

所以如果主机如果是小端的话,需要先把数据转换成大端

–可以调用系统接口把主机字节序转换成网络字节序

在这里插入图片描述

h表示host,n表示network,l表示32位长整数,s表示16位短整数

套接字(socket)编程

套接字编程的种类有:

1.域间套接字编程(同一个机器内使用的) 2.原始套接字编程 3.网络套接字编程(用户间的网络通信)

套接字编程有三类常见的表示通信地址的结构体

在这里插入图片描述

struct sockaddr是其余这俩的"父类"

struct sockaddr {
    sa_family_t sa_family;  /* 地址类型(如 AF_INET、AF_UNIX 等) */
    char        sa_data[14];/* 地址数据,长度为 14 字节 */
};//这是通用地址结构体
struct sockaddr_in {
    sa_family_t    sin_family; /* 地址族,必须为 AF_INET(标识 IPv4) */
    in_port_t      sin_port;   /* 16 位端口号(需用 htons 转换为网络字节序) */
    struct in_addr sin_addr;   /* 32 位 IPv4 地址(网络字节序) */
    char           sin_zero[8];/* 填充字段,使结构大小与 sockaddr 对齐 */
};
/* 配套的 IPv4 地址结构体 */
struct in_addr {
    uint32_t s_addr; /* IPv4 地址的 32 位二进制值(网络字节序) */
};
//这是IPv4的专用地址结构体

socket常见的系统调用接口

这些接口那三种结构体都能用哈

在这里插入图片描述

这个的作用是创建套接字

返回值:成功的话返回一个套接字描述符(也属于文件描述符哈) 失败返回-1,可以用errno查哪错了

形参:

domain:指定协议族 常填这三种

AF_INET:IPv4 协议族

AF_INET6:IPv6 协议族

AF_UNIX:UNIX 域套接字

type:指定套接字类型

SOCK_DGRAM:数据报套接字(UDP用这个)

SOCK_STREAM:流式套接字(TCP用这个)

SOCK_RAW:原始套接字

protocol:一般都是传0就行了

在这里插入图片描述

作用:将套接字与本地地址(IP 地址 + 端口号)绑定

形参:

socket:要绑定的套接字的文件描述符

addr:要绑定的地址的地址结构体的地址(记得强转)

addrlen:地址结构体的长度

返回值:成功返回0;失败返回-1,可以用errno查看具体原因

引申:这个是在void*可以表示通用接口前设计的,所以用的还是const struct sockaddr*

注意:云服务器禁止直接绑定公网 IP,但是虚拟机可以–因为云服务器一般都不只有一个网卡,属于不同网卡在不同网络的话就会有多个IP

解决方法:采用 “任意地址绑定”

引申:

在这里插入图片描述

这个是内存清0函数,可以用来把结构体里面的数据清除

eg:bzero(&addr, sizeof(addr))memset等效,甚至没memset

在这里插入图片描述

作用:

recv:用于面向连接的套接字(如 TCP)接收数据,从已建立连接的套接字中读取数据到缓冲区

flags0的话跟read的效果一样

recvfrom:用于无连接的套接字(如 UDP)接收数据,同时获取发送方的地址信息

注意:如果接收不到信息的话,是会阻塞等待的

这俩的返回值:成功返回实际接收的字节数,失败返回-1,可以用errno看失败的原因

形参:

sockfd:套接字的文件描述符

buf:接收数据的缓冲区指针

len:缓冲区长度

flags:操作标志,一般传0,表示阻塞状态

src_addr:存储客户端地址的结构体的指针,这个是输出型参数–记得强转

addrlen:客户端地址长度的指针,这个是输入输出型参数–输入的话是为了防止因结构体大小不匹配导致的内存溢出或数据解析错误

在这里插入图片描述

作用:

send:用于面向连接的套接字(如 TCP)发送数据

–flags填:MSG_OOB的话,表示传的是紧急数据(同样,recv也要填这个,不然读取的不是紧急数据–但是填了这个的话读的只能是紧急数据)

sendto:用于无连接的套接字(如 UDP)发送数据

这俩的返回值:成功返回0,失败返回-1,可以用errno查出错原因

形参:

sockfd:套接字文件描述符

buf:待发送数据的缓冲区指针

len:待发送数据的长度

flags:操作标志,一般传0,表示有阻塞状态

dest_addr:指向目标地址的指针

addrlen:目标地址的长度

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这些是地址转换函数–将IPv4用点分十进制表示的字符串地址跟二进制的网络字节序地址之间相互转换

字符串转in_addr的函数有inet_aton inet_addr inet_pton

in_addr转字符串的函数有inet_ntoa inet_ntop

其中inet_ptoninet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr

但是:inet_ntoa把结果放到自己内部的一个静态存储区, 这样第二次调用时的结果会覆盖掉上一次的结果–所以一般不用这个

引申:UDPTCPsocket是全双工的,也就是是允许被同时读写的

© 版权声明

相关文章