【项目 计网4】4.11 socket地址 4.12 IP地址转换函数 4.13TCP通信流程 4.14socket函数

news2024/10/5 20:19:15

文章目录

    • 4.11 socket地址
      • 通用 socket地址
      • 专用 socket地址
    • 4.12 IP地址转换函数(字符串ip -> 整数)
    • 4.13TCP通信流程
    • 4.14socket函数


4.11 socket地址

socket地址其实是一个结构体,封装端口号和IP等信息。后面的socket相关的api中需要使用到这个socket地址。

客户端 -> 服务器(IP, Port)

通用 socket地址

socket 网络编程接口中表示 socket 地址的是结构体 sockaddr,其定义如下:

#include <bits/socket.h>
struct sockaddr {
	sa_family_t sa_family; //表示属于哪一类型的地址/协议
	char sa_data[14]; //具体的地址
};
typedef unsigned short int sa_family_t;

sa_family 成员是地址族类型(sa_family_t)的变量。地址族类型通常与协议族类型对应。 (sa_family = PF_UNIX 或者其他的 )

常见的宏 :
协议族(PF: protocol family,也称 domain)和对应的地址族(AF: address family)如下所示:
在这里插入图片描述宏 PF_* 和 AF_* 都定义在 bits/socket.h 头文件中,且后者与前者有完全相同的值,所以二者通常混用。
sa_data 成员用于存放 socket 地址值。但是,不同的协议族的地址值具有不同的含义和长度,如下所示:
在这里插入图片描述
由上表可知,14 字节的 sa_data 根本无法容纳多数协议族的地址值。因此,Linux 定义了下面这个新的通用的 socket 地址结构体,这个结构体不仅提供了足够大的空间用于存放地址值,而且是内存对齐的。

#include <bits/socket.h>
struct sockaddr_storage
{
	sa_family_t sa_family; //表示协议\地址类型
	unsigned long int __ss_align;  //用于内存对齐 先不管
	char __ss_padding[ 128 - sizeof(__ss_align) ];  //存放具体地址数据
};
typedef unsigned short int sa_family_t;

专用 socket地址

很多网络编程函数诞生早于 IPv4 协议,那时候都使用的是 struct sockaddr 结构体,为了向前兼容,现在sockaddr 退化成了(void *)的作用,传递一个地址给函数,至于这个函数是 sockaddr_in 还是sockaddr_in6,由地址族确定,然后函数内部再强制类型转化为所需的地址类型。
在这里插入图片描述UNIX 本地域协议族使用如下专用的 socket 地址结构体:

#include <sys/un.h>
struct sockaddr_un
{
	sa_family_t sin_family;
	char sun_path[108];
};

TCP/IP 协议族有== sockaddr_in== 和 sockaddr_in6 两个专用的 socket 地址结构体,它们分别用于 IPv4 和IPv6:

//最重要
#include <netinet/in.h>
struct sockaddr_in
{
	sa_family_t sin_family; /* __SOCKADDR_COMMON(sin_) */
	in_port_t sin_port; /* Port number. */ //2字节端口号
	struct in_addr sin_addr; /* Internet address. */ //4字节IP地址
	/* Pad to size of `struct sockaddr'. */
	unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE - 
		sizeof (in_port_t) - sizeof (struct in_addr)]; //这一长条都是剩余部分
};

struct in_addr
{
	in_addr_t s_addr;
};

struct sockaddr_in6
{
	sa_family_t sin6_family;
	in_port_t sin6_port; /* Transport layer port # */
	uint32_t sin6_flowinfo; /* IPv6 flow information */
	struct in6_addr sin6_addr; /* IPv6 address */
	uint32_t sin6_scope_id; /* IPv6 scope-id */
};

typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))

所有专用 socket 地址(以及 sockaddr_storage)类型的变量在实际使用时都需要转化为通用 socket 地址类型 sockaddr(强制转化即可),因为所有 socket 编程接口使用的地址参数类型都是 sockaddr。

因为sockaddr只有16字节的char,端口和IP地址分别是short和int,如果要存放的话就要转换成逐个字节单独存放,很麻烦。所以有了sockaddr_in。存放的时候直接调用in_port_t sin_port; struct in_addr sin_addr; 这两个成员,直接赋值就行。
只是!所有相关函数的形参都是sockaddr,所以在调用API的时候需要将sockaddr_in强制转换成 sockaddr。

4.12 IP地址转换函数(字符串ip -> 整数)

字符串ip -> 整数 ,主机、网络字节序的转换

通常,人们习惯用可读性好的字符串来表示 IP 地址,比如用点分十进制字符串表示 IPv4 地址,以及用十六进制字符串表示 IPv6 地址。但编程中我们需要先把它们转化为整数(二进制数)方能使用。
而记录日志时则相反,我们要把整数表示的 IP 地址转化为可读的字符串。

下面 3 个函数可用于用点分十进制字符串表示的 IPv4 地址和用网络字节序整数表示的 IPv4 地址之间的转换:(IPV4 <-> 网络字节序(大端))

//不建议使用 只能在IPV4使用
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
int inet_aton(const char *cp, struct in_addr *inp);
char *inet_ntoa(struct in_addr in);

/*
struct in_addr *inp 其实就是4字节的IP地址
struct in_addr
{
	in_addr_t s_addr;
};
typedef uint32_t in_addr_t;
typedef unsigned int uint32_t;
*/

下面这对更新的函数也能完成前面 3 个函数同样的功能,并且它们同时适用 IPv4 地址和 IPv6 地址:

#include <arpa/inet.h>
// p:点分十进制的IP字符串(point), n:表示network,网络字节序的整数
int inet_pton(int af, const char *src, void *dst);
	af:地址族: AF_INET AF_INET6
	src:需要转换的点分十进制的IP字符串
	dst:转换后的结果保存在这个里面
	
// 将网络字节序的整数,转换成点分十进制的IP地址字符串
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
	af:地址族: AF_INET AF_INET6
	src: 要转换的ip的整数的地址
	dst: 转换成IP地址字符串保存的地方
	size:第三个参数的大小(数组的大小)
	返回值:返回转换后的数据的地址(字符串),和 dst 是一样的

#include <stdio.h>
#include <arpa/inet.h>

int main() {

    // 创建一个ip字符串,点分十进制的IP地址字符串
    char buf[] = "192.168.1.4";
    unsigned int num = 0;

    // 将点分十进制的IP字符串转换成网络字节序的整数
    inet_pton(AF_INET, buf, &num);
    unsigned char * p = (unsigned char *)&num;
    printf("%d %d %d %d\n", *p, *(p+1), *(p+2), *(p+3));


    // 将网络字节序的IP整数转换成点分十进制的IP字符串
    //ip地址在整数类型的时候 是四字节
    //转换成字符串以后一个数字就是1字节,所以至少15 xxx.xxx.xxx.xxx
    //还有最后一个字符串结束符 所以是16
    char ip[16] = "";
    const char * str =  inet_ntop(AF_INET, &num, ip, 16);
    printf("str : %s\n", str);
    printf("ip : %s\n", str);
    printf("%d\n", ip == str);

    return 0;
}

显示结果
在这里插入图片描述

4.13TCP通信流程

在这里插入图片描述
在这里插入图片描述
bind()函数绑定服务端的ip和端口号,accept()函数是阻塞的,接受客户端连接请求,创建一个新的文件描述符fd用于读写缓冲区,与客户端进行通信。监听时的是另一个fd专门用来监听。

// TCP 通信的流程
// 服务器端 (被动接受连接的角色)
1. 创建一个用于监听的套接字
- 监听:监听有客户端的连接
- 套接字:这个套接字其实就是一个文件描述符
2. 将这个监听文件描述符和本地的IP和端口绑定(IP和端口就是服务器的地址信息)
- 客户端连接服务器的时候使用的就是这个IP和端口
3. 设置监听,监听的fd开始工作(fd对应着一个读缓冲区和写缓冲区。当内核读缓冲区有数据,就说明被连接了。但这个工作不是程序员监听,是程序自己判断的。)
4. 阻塞等待,当有客户端发起连接,解除阻塞,接受客户端的连接,会得到一个和客户端通信的套接字(fd)
5. 通信
- 接收数据
- 发送数据
6. 通信结束,断开连接

// 客户端
1. 创建一个用于通信的套接字(fd)
2. 连接服务器,需要指定连接的服务器的 IP 和 端口
3. 连接成功了,客户端可以直接和服务器通信
- 接收数据
- 发送数据
4. 通信结束,断开连接

4.14socket函数

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h> // 包含了这个头文件,上面两个就可以省略
int socket(int domain, int type, int protocol);
- 功能:创建一个套接字
- 参数:
- domain: 协议族
     AF_INET : ipv4
     AF_INET6 : ipv6
     AF_UNIX, AF_LOCAL : 本地套接字通信(进程间通信)
- type: 通信过程中使用的协议类型
     SOCK_STREAM : 流式协议
     SOCK_DGRAM : 报式协议
- protocol : 具体的一个协议。一般写0
    - SOCK_STREAM : 流式协议默认使用 TCP
    - SOCK_DGRAM : 报式协议默认使用 UDP
- 返回值:
    - 成功:返回文件描述符,操作的就是内核缓冲区。
    - 失败:-1

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); // socket命- 功能:绑定,将fd 和本地的IP + 端口进行绑定
- 参数:
- sockfd : 通过socket函数得到的文件描述符
- addr : 需要绑定的socket地址,这个地址封装了ip和端口号的信息
- addrlen : 第二个参数结构体占的内存大小
- 返回值:
    - 成功:返回0
    - 失败:-1
    
int listen(int sockfd, int backlog); // /proc/sys/net/core/somaxconn
- 功能:监听这个socket上的连接
- 参数:
- sockfd : 通过socket()函数得到的文件描述符
- backlog : 未连接的和已经连接的和的最大值, 5
- 返回值:
    - 成功:返回0
    - 失败:返回-1 并设置错误号

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- 功能:接收客户端连接,默认是一个阻塞的函数,阻塞等待客户端连接
- 参数:
- sockfd : 用于监听的文件描述符
- addr : 传出参数,记录了连接成功后客户端的地址信息(ip,port)
- addrlen : 指定第二个参数的对应的内存大小
- 返回值:
- 成功 :用于通信的文件描述符
- -1 : 失败

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 功能: 客户端连接服务器
- 参数:
   - sockfd : 用于通信的文件描述符
   - addr : 客户端要连接的服务器的地址信息
   - addrlen : 第二个参数的内存大小
- 返回值:成功 0, 失败 -1
 
ssize_t write(int fd, const void *buf, size_t count); // 写数据
ssize_t read(int fd, void *buf, size_t count); // 读数据

解释:backlog : 未连接的和已经连接的和的最大值, 5

  1. 未连接队列(Unconnected Queue):这是一种用于存储尚未建立连接的请求或数据包的队列。在网络通信中,未连接队列通常用于临时存储未经身份验证或握手的数据包,等待进一步处理或连接。这些数据包可能需要进一步的验证、身份确认或其他操作,然后才能进入已连接状态。
  2. 已连接队列(Connected Queue):这是一种用于存储已经建立连接并正在进行通信的请求或数据包的队列。已连接队列中的数据包是已经通过身份验证和握手等步骤,与远程主机建立了连接的数据。这些数据包可以在连接的上下文中进行通信和交换。
    这二者总和一般设置成5就够用了
    使用命令 cat /proc/sys/net/core/somaxconn 可以看到可以设置的最大值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/860985.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Eolink 出席 QECon 大会,引领「AI+API」技术的革新浪潮

7月28日-29日&#xff0c;第八届 QECon 质量效能大会在北京成功召开。大会聚焦“数生智慧&#xff0c;高质量发展新引擎”&#xff0c;深入探讨如何利用数字化和智能化技术推动软件质量的发展&#xff0c;进而为高质量的经济发展提供新的引擎。作为国内 API 全生命周期解决方案…

【计算机组成原理】24王道考研笔记——第三章 存储系统

第三章 存储系统 一、存储系统概述 现代计算机的结构&#xff1a; 1.存储器的层次结构 2.存储器的分类 按层次&#xff1a; 按介质&#xff1a; 按存储方式&#xff1a; 按信息的可更改性&#xff1a; 按信息的可保存性&#xff1a; 3.存储器的性能指标 二、主存储器 1.基本…

Oracle database 静默安装 oracle 11g 一键安装

基于oracle安装包中应答文件实现一键安装 支持环境&#xff1a; Linux &#xff1a;centerOS 7 oracle &#xff1a;11.2.0 Oracle应答文件 runInstaller应答文件 /database/response/db_install.rsp netca应答文件 /database/response/netca.rsp dbca应答文件 /database/re…

FFmpeg音视频处理技术:基于Linux下QT Creator的FFmpeg环境搭建(史上最全)

前言 阅读本文章的小伙伴需要注意&#xff0c;本作者主要是从4个方面进行FFmpeg环境的搭建&#xff08;完全适应利用常见操作系统平台进行FFmpeg音视频开发&#xff09;&#xff0c;大家根据需要自行选择相应的环境进行搭建&#xff1a; &#xff08;1&#xff09;Linux&#x…

【Java并发】ReentrantLock的实现原理

文章目录 ReentrantLock是什么&#xff1f;ReentrantLock底层源码&#xff1a;ReentrantLock底层原理图解&#xff1a;&#xff08;以NonfairSync举例&#xff09; ReentrantLock是什么&#xff1f; synchronized关键字是一种隐式锁&#xff0c;即它的加锁与释放是自动的&…

Android 开发面试中,面试官最喜欢问那些问题?

作者&#xff1a;小谢 “你遇到过哪些高质量的Android面试&#xff1f;” [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Pc1xZw5-1691675604271)(//upload-images.jianshu.io/upload_images/24388310-aa3c732481d0749f.png?imageMogr2/auto-orie…

自动脱扣型绝缘靴(手套)耐压支架操作步骤

一、概述 KDJS-8Q自动脱扣型绝缘靴&#xff08;手套&#xff09;耐压支架是根据《DLT 976-2017 带电作业工具、装置和设备预防性试验规程》、《DLT 1476-2015电力安全工器具预防性试验规程》、《GBT 17622-2008带电作业用绝缘手套》、《CB21148 2020足部防护 安全鞋》等…

【java】java项目在idea中Build Project或Rebuild Project一直进行不完

问题场景 我项目进行重新构建的时候&#xff0c;项目构建到某一个位置就一直不动了 解决方法 1.清理idea缓存 2.加大idea的内存 File -> Setting

在 Delphi 的 TRichEdit 中插入图片并保存为html文件

当在 Delphi 中使用 TRichEdit 组件时&#xff0c;有时需要将图片插入到文本中。下面详细介绍了如何在 TRichEdit 中插入图片。 引言&#xff1a; TRichEdit 组件是 Delphi 中常用的文本编辑控件&#xff0c;它不仅可以显示文本内容&#xff0c;还可以插入图片&#xff0c;丰富…

springboot汽车租赁后台java出租客户管理jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 springboot汽车租赁后台 系统有1权限&#xff1a;管理…

SCI论文中字体和图片字体大小的要求

SCI论文中字体和图片字体大小的要求 文章目录 1. American Chemical Society(ACS)要求2. Nature要求 1. American Chemical Society(ACS)要求 https://www.zhihu.com/question/380612293?utm_id0 2. Nature要求

章节1:HTTP协议回顾

章节1&#xff1a;HTTP协议回顾 HTTP请求方式 get请求&#xff1a;我们通常用其发起查询。 post请求&#xff1a;我们用其来向服务器提交数据。 HTTP请求格式 第一行为请求行。 HTTP响应格式 HTTP特点 请求应答模式灵活可扩展可靠传输无状态 stateless

网神 SecGate 3600 防火墙任意文件上传漏洞复现(HW0day)

0x01 产品简介 网神SecGate3600下一代极速防火墙&#xff08;NSG系列&#xff09;是基于完全自主研发、经受市场检验的成熟稳定网神第三代SecOS操作系统 并且在专业防火墙、VPN、IPS的多年产品经验积累基础上精心研发的高性能下一代防火墙 专门为运营商、政府、军队、教育、大型…

推出 Elasticsearch 查询语言 (ES|QL)

作者&#xff1a;Costin Leau 我很高兴地宣布&#xff0c;经过大约一年的开发&#xff0c;Elasticsearch 查询语言 (ES|QL) 已准备好与世界共享&#xff0c;并已登陆 Elasticsearch 存储库。 ES|QL 是 Elasticsearch 原生的强大声明性语言&#xff0c;专为可组合性、表现力和速…

网络加速与文件传输软件:如何通过优化网络提升文件传输速度

在信息化社会&#xff0c;文件传输是人们生活和工作中必不可少的一个环节。但是&#xff0c;由于网络环境的多样性和传输过程中可能出现的各种问题&#xff0c;文件传输速度经常受到影响。因此&#xff0c;如何优化网络以提高文件传输速度成为了一个重要的课题。本文将探讨网络…

Mybatis-plus 异常:Not Found TableInfoCache

标题&#xff1a;Mybatis-plus 异常&#xff1a;Not Found TableInfoCache Mybatis-plus 是一个流行的基于 Mybatis 的增强工具包&#xff0c;可以极大地简化数据库操作。然而&#xff0c;在使用 Mybatis-plus 过程中&#xff0c;可能会遇到一些异常情况&#xff0c;其中之一就…

mysql基础之触发器的简单使用

1.建立学生信息表 -- 触发器 -- 建立学生信息表 create table s1(id int unsigned auto_increment,name varchar(30),score tinyint unsigned,dept varchar(50),primary key(id) );2.建立学生补考信息表 -- 建立学生补考信息表 create table s2 like s1;3.建立触发器&#xf…

【excel技巧】excel公式如何隐藏?

Excel文件中最重要的除了数据还有就是一些公式了&#xff0c;但是只要点击单元格&#xff0c;公式就能显示出来&#xff0c;如果不想别人看到公式应该如何设置呢&#xff1f;今天分享隐藏excel单元格数据的方法。 选中单元格&#xff0c;点击右键打开【设置单元格格式】&#x…

【Linux】云服务器自动化部署VuePress博客(Jenkins)

前言 博主此前是将博客部署在 Github Pages&#xff08;基于 Github Action&#xff09;和 Vercel 上的&#xff0c;但是这两种部署方式对于国内用户很不友好&#xff0c;访问速度堪忧。因此将博客迁移到自己的云服务器上&#xff0c;并且基于 Jenkins&#xff08;一款开源持续…

最强自动化测试框架Playwright-(2)实用操作

元素定位 定位器是playwright自动等待和重试功能的核心部分。简而言之&#xff0c;定位器表示一种随时在页面上查找元素的方法。 Locators | Playwright Python 如下这些是推荐的 page.get_by_role&#xff08;&#xff09; 按显式和隐式辅助功能属性进行定位。 page.get…