浅谈 Linux 网络编程 - Server 端模型、sockaddr、sockaddr_in 结构体

2024-02-29 15:20

本文主要是介绍浅谈 Linux 网络编程 - Server 端模型、sockaddr、sockaddr_in 结构体,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 前言
    • 前置知识
    • Server 端核心模型 【重点】
    • 相关函数 【重点】
      • socket 函数
      • bind 函数
      • listen 函数
      • accept 函数
      • close 函数
    • sockaddr 数据结构 【重点】

前言

本文主要是对 Linux 网络编程中,Server 端的模型、相关函数 以及 sockaddr、sockaddr_in 结构体做介绍。

前置知识

① 理解啥是 socket ,可参考:浅谈 Linux 网络编程 socket

② 理解 字节流转换 函数,可参考:浅谈 Linux 网络编程 - 网络字节序

Server 端核心模型 【重点】

一定要记住 server 端的套路:

①创建 socket()
②绑定 ip + port,bind()
③设置连接上限,listen()
④阻塞,监听客户端的连接,accept()
⑤业务逻辑 ,read()/write()
⑥关闭 socket,close()

以上几个步骤是固定死的,直接背下来,把"前置知识"和接下来要讲解的 函数 理解后,我们按照这个套路就能写出 Server 端的 socket 模型。

还有两个需要记住的:

  1. listen() 这步是用来设置 Server 端的连接上限,而不是监听来自客户端的连接,不要被名字迷惑了。
  2. accept() 函数才是阻塞监听来自客户端的连接。

相关函数 【重点】

socket 函数

#include <sys/socket.h>
int socket(int domain, int type, int protocol); 创建一个 套接字

		domain:指定协议族或地址族,例如:AF_INET、AF_INET6、AF_UNIXtype:指定套接字的类型,例如:SOCK_STREAM、SOCK_DGRAMSOCK_STREAM(流式套接字,提供面向连接的可靠传输)SOCK_DGRAM(数据报套接字,提供无连接的不可靠传输)protocol: 指定具体的协议编号,通常为0表示自动选择合适的协议。返回值:成功: 新套接字所对应文件描述符失败: -1 errno对于这个函数的参数,一般是这样的:fd = socket (AF_INET, SOCK_STREAM, 0);

bind 函数

这个函数的第二个参数是重点,不懂的,建议先去看看本篇的【sockaddr 数据结构】章节,再回来看 bind 函数的参数传递。

#include <arpa/inet.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
给 socket 绑定一个 地址结构 (IP+port)

		sockfd: socket() 函数返回值struct sockaddr_in addr;  // 重点掌握这个结构体addr.sin_family = AF_INET;addr.sin_port = htons(8888);addr.sin_addr.s_addr = htonl(INADDR_ANY);   // 获取本机任意可用的 ip,转换成网络字节流addr: 传入参数(struct sockaddr *)&addraddrlen: sizeof(addr) (服务端)地址结构的大小。返回值:成功:0失败:-1 errno

listen 函数

该函数是设置 server 连接上限的。

int listen(int sockfd, int backlog); 设置同时与服务器建立连接的上限数。(同时进行3次握手的客户端数量)

	sockfd: socket() 函数的返回值backlog:上限数值。最大值 128.返回值:成功:0失败:-1 errno	

accept 函数

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 阻塞等待客户端建立连接,成功的话,返回一个与客户端成功连接的 socket 文件描述符。

		sockfd: socket() 函数的返回值struct sockaddr_in cli_addr;  cli_addr:是传出参数。成功与服务器建立连接的那个 客户端的地址结构(IP+port),因为是传出参数, cli_addr 成员的值由 accept 函数赋值socklen_t clit_addr_len = sizeof(cli_addr);addrlen:是传入传出参数。客户端结构体大小, &clit_addr_len。入:cli_addr 的大小。 出:客户端 cli_addr 实际大小。返回值:成功:返回能与客户端进行数据通信的 socket 对应的文件描述。失败: -1 , errno

重点要注意的就是 accept 返回值,accept 返回的 socket 才是真正与 client 建立连接的 socket。
在这里插入图片描述

在"前置知识"中说过,socket 是成对出现的,所以 client 和 server 都有自己的 socket,需要注意的是,客户端的socket (cfd) 连接的是 server 的第二个 socket( fd2 )。

server 端的两个套接字:
socket 函数创建的是 监听套接字(fd1),用于监听来自客户端的连接请求,和进行端口、IP 绑定。
由 accept 函数创建的是用于通信的套接字(fd2),用于和客户端建立连接,称为 通信套接字

close 函数

这个没啥好说的,就是关闭 socket。

close(socket_fd);

sockaddr 数据结构 【重点】

这个 sockaddr 和 bind 函数的第二个参数 " const struct sockaddr *addr "有关。

在早期的时候,使用的是 sockaddr,后来出现了新的、用于 ipv4 的 sockaddr_in,所以现在使用的都是 sockaddr_in。

sockaddr_in 相比于 sockaddr,二者的大小都是一样的,只是在空间划分上分的更细:
在这里插入图片描述
按以上的说法,就是需要在 bind 函数的第二个参数传入 sockaddr_in 类型的结构体变量,但是 bind 函数的声明是这样的:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
很明显,第二个参数是 sockaddr 类型,因此我们在传 sockaddr_in 类型的参时需要做强转,例如:

struct sockaddr_in addr;
// 这里省略给 addr 的成员赋值
... ... // 将 sockaddr_in 类型的结构体变量 addr,强转成 sockaddr 类型的结构体变量
bind(fd,  ( struct sockaddr *) &addr,  addrlrn);

sockaddr_in 结构体的内部也需要关注,因为 sockaddr_in 是一个传入参数,也就是需要先给 sockaddr_in 的结构体变量(addr)赋值,然后再将结构体变量(addr)传入bind函数。
sockaddr_in 结构体内部是这样的:
在这里插入图片描述
给 sockaddr_in 的成员变量赋值:

struct sockaddr_in addr;addr.sin_family = AF_INET;  // ip v4
addr.sin_port = htons(8888);  // 本地字节序 转 网络字节序 【前置知识 中有介绍】
addr.sin_addr.s_addr = htonl(INADDR_ANY);  // 获取本机的任一有效 ip,本地字节序 转 网络字节序 【前置知识 中有介绍】

以上就是对 sockaddr_in 结构体成员的赋值和 bind 的第二个参数传递的介绍。

这篇关于浅谈 Linux 网络编程 - Server 端模型、sockaddr、sockaddr_in 结构体的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/759249

相关文章

MySQL的JDBC编程详解

《MySQL的JDBC编程详解》:本文主要介绍MySQL的JDBC编程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、前置知识1. 引入依赖2. 认识 url二、JDBC 操作流程1. JDBC 的写操作2. JDBC 的读操作总结前言本文介绍了mysq

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

Debian 13升级后网络转发等功能异常怎么办? 并非错误而是管理机制变更

《Debian13升级后网络转发等功能异常怎么办?并非错误而是管理机制变更》很多朋友反馈,更新到Debian13后网络转发等功能异常,这并非BUG而是Debian13Trixie调整... 日前 Debian 13 Trixie 发布后已经有众多网友升级到新版本,只不过升级后发现某些功能存在异常,例如网络转

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

linux系统上安装JDK8全过程

《linux系统上安装JDK8全过程》文章介绍安装JDK的必要性及Linux下JDK8的安装步骤,包括卸载旧版本、下载解压、配置环境变量等,强调开发需JDK,运行可选JRE,现JDK已集成JRE... 目录为什么要安装jdk?1.查看linux系统是否有自带的jdk:2.下载jdk压缩包2.解压3.配置环境

Linux搭建ftp服务器的步骤

《Linux搭建ftp服务器的步骤》本文给大家分享Linux搭建ftp服务器的步骤,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录ftp搭建1:下载vsftpd工具2:下载客户端工具3:进入配置文件目录vsftpd.conf配置文件4:

Python异步编程之await与asyncio基本用法详解

《Python异步编程之await与asyncio基本用法详解》在Python中,await和asyncio是异步编程的核心工具,用于高效处理I/O密集型任务(如网络请求、文件读写、数据库操作等),接... 目录一、核心概念二、使用场景三、基本用法1. 定义协程2. 运行协程3. 并发执行多个任务四、关键