【linux】套接字学习

本文详细阐述了TCP/IP四层协议的工作原理,包括数据包的封装与解封装,IP地址和MAC地址的作用,以及套接字(如UDP)的使用,重点介绍了bind、connect和accept等网络通信操作,以及网络字节序转换的相关函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TCP/IP四层协议,每层都有自己的协议方案,每层协议都要有自己的协议报头。从上到下递交数据时,要添加报头;从下到上交付数据时,要去掉报头。
不同协议层对数据包有不同的称谓,在传输层叫做段,在网络层叫做数据报,在链路层叫做帧。

在这里插入图片描述
一般而言:
对于一台主机,它的操作系统内核实现了从传输层到物理层的内容;
对于一台路由器,它至少实现了从网络层到物理层的内容;
对于一台交换机,它至少实现了从数据链路层到物理层的内容;
对于集线器,它只实现了物理层。

局域网中两台主机是可以直接通信的。
在这里插入图片描述
IP地址(公网IP):是在IP协议中,用来标识网络中不同主机的地址。
IPv4是32位的,通常也使用“点分十进制”的字符串来表示IP地址,而点分割的每个数字的范围是0-255。
MAC地址:用来识别数据链路层中的节点,Linux下可以通过ifconfig指令查看主机的MAC地址。
MAC地址是48位的,一般用16进制数字加冒号的形式表示。
在这里插入图片描述
端口号是传输层协议的内容。端口号是16位的。
理解端口号和进程ID:
一个进程可以和多个端口号进行绑定,一个端口号最多只能和一个进程进行关联。


TCP/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);

如果主机是小端字节序,这些函数将参数做相应的大端转换然后返回;如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。
常见的套接字有域间套接字,原始套接字,网络套接字等。针对不同的应同场景选用不同的套接字,对应的需要不同的套接字接口,但是Linux将这些接口做了统一。
UDP:
创建套接字:
在这里插入图片描述
在这里插入图片描述
domain
在这里插入图片描述
type:通信种类(字节流/数据报)
在这里插入图片描述
绑定:
在这里插入图片描述
在这里插入图片描述
bind的作用是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。
服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接。
客户端没有必要通过手动bind来固定一个端口号,客户端的端口号可以由内核自动分配,否则如果在同一台机器上启动多个客户端,就可能会出现端口号被占用的情况;服务器也不是必须调用bind,但如果服务器不调用bind,内核会自动给服务器分配监听端口,每次启动服务器时端口号都不一样,使客户端连接服务器就会遇到麻烦。
struct sockaddr*是一个通用指针类型,addr参数实际上可以接受多种协议的sockaddr结构体,而他们的长度各不相同,所以需要第三个参数addrlen来指定结构体的长度。
对addr参数初始化的一个示例:

// 将整个结构体清零
bzero(&servaddr, sizeof(servaddr));
// 设置地址类型为INADDR_ANY, 表示本地的任意IP地址
// 因为服务器可能有多个网卡,每个网卡可能绑定多个IP地址,设置成INADDR_ANY可以在所有IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP地址
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);

ip地址的转化:
点分十进制字符串转in_addr的函数:

int inet_aton(const char *strptr, struct in_addr *addrptr);
in_addr_t inet_addr(const char *strptr);
int inet_pton(int family, const char *strptr, void *addrptr);

in_addr转点分十进制字符串的函数:

char *inet_ntoa(struct in_addr inaddr);
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

inet_ptoninet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr,因此函数接口是void *addrptr
在多线程环境下,推荐使用inet_ntop,这个函数由调用者提供一个缓冲区保存结果,可以规避线程安全问题。
在这里插入图片描述
在这里插入图片描述
查看启动的UDP链接:
在这里插入图片描述

TCP:
在这里插入图片描述
在这里插入图片描述
listen声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接等待状态,如果接收到更多的连接请求就忽略。backlog的设置不会太大(一般是5)。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
三次握手完成后,服务器调用accept接收连接。如果服务器调用accept时还没有客户端的连接请求,就会阻塞等待直到客户端连接上来。
addr是一个输出型参数,传出客户端就的地址和端口号,如果addr参数为空,表示不关心客户端的地址。
addrlen参数是一个输入输出型参数,传入的是调用者提供的缓冲区addr的长度,避免缓冲区的溢出问题;传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。

sudo yum install telnet*
ctrl + ]
换行
通信
ctrl + ]
quit

在这里插入图片描述
客户端需要调用connect连接服务器。connectbind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿阿阿顺Yaya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值