Linux网络套接字编程——创建并绑定

目录

网络字节序

socket编程接口

socket

bind


如果将进程比作一个房子,那套接字相当于是一扇门,通向与外界通信的通道。

在网络中,如何理解套接字呢,时刻记住套接字是为了标识互联网中的某一台主机上的某一个进程,因此它就是IP地址 + 端口号。

现在你完全可以把套接字当成一个结构体,里面包含了这台主机的IP地址和端口号。(只为了方便理解,实际中可能并不止如此)

在介绍套接字前,先来认识一下网络字节序

网络字节序

计算机的内存分为大端和小端存储数据,而不同的主机若想通信,则必须消除这个差别。

先来了解如下两个事实

发送主机通常将发送缓冲区的数据按照地址从低到高发出;

接受主机也是按照地址从低到高的顺序保存到接收缓冲区中;

因此,网络数据流规定:先发出数据的是低地址,后发出数据的是高地址。

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

这样,小端机发送和接收数据时都需要将按大端序的数据转化为小端。

关于本地字节序转网络字节序,linux提供了以下系统调用

#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);

乍一看有四个接口,其实很好记,h代表host即本地,n代表net即网络,l即long表示长整型32位,s

即short表示短整型16位。

使用这些系统调用就可以实现本地字节序和网络字节序的相互转换

socket编程接口

先列出常用的socket api

#include <sys/types.h>     
#include <sys/socket.h>// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address, socklen_t address_len);// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address, socklen_t* address_len);// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

现在可能看不太懂,下面会讲解每个接口及其使用。

socket

第一个domain参数表示你将要使用的协议族,能选择的协议族定义在<sys/socket.h>

有许多可用的协议族,在这只重点谈AF_INET即用于网络通信的IPv4协议。

选择AF_INET代表着创建用于网络通信的套接字。

第二个type参数是套接字的类型,这里能用到的有SOCK_STREAM和SOCK_DGRAM,第一个是用于TCP的,能提供可靠的通信服务,第二个用于UDP,提供不可靠通信。

还有 SOCK_RAW即原始网络套接字,直接基于IP协议而不是基于TCP\UDP。

protocol参数传0即可。

返回值是一个一个文件描述符,通过该文件描述符即可像操作普通文件一样对套接字进行操作。

若创建失败则返回-1。

像对普通文件调用write和read一样对套接字进行读写。

这里指出,windows系统的套接字创建不会返回类似文件描述符这种描述文件的值,因为windows并不将套接字看作文件类型,而linux则通过“一切皆文件”的思想,为套接字的操作提供了与普通文件统一的接口。

int fd = socket(AF_INET, SOCK_DGRAM, 0);

这样就能创建一个UDP套接字并能通过fd来对它进行操作了,现在,走向下一步。

bind

前面把套接字比作是门,到目前为止我们已经造出了一扇门,但还不能使用,因为还没有将门“安装”在房子上。接下来我们要将套接字绑定到某个进程,即完成“安装”工作。

第一个sockfd参数决定你要绑定哪个套接字,就是上面介绍的socket函数的返回值。

要理解第二个参数,先来了解下面的知识:

套接字实际上并不是只有现在讲的网络套接字,有三种套接字,三种都使用的是同一套接口,

当使用原始网络套接字,传入sockaddr结构;使用基于TCP\UDP的网络套接字,传入sockaddr_in结构(in是inet),使用本地套接字,则需要传入sockaddr_un结构。

也就是说,不同种类的套接字需要在这第二个参数传入不同的结构体。

这实际上是一种多态的思想,操作系统的设计者期望使用统一的接口,对于不同的种类的套接字,提供不同的服务。而C语言并不支持多态,于是将sockaddr作为基类来设计接口。并且,上面提到的三个不同的结构,会有一个公共的16位的字段来告诉操作系统,自己是哪个种类的套接字。

因此,我们使用的网络套接字,在这里传入一个sockaddr_in的结构体即可。这个结构体中一定会包含IP地址和端口号这两个信息,这两个字段是需要用户自己填充的。

typedef uint16_t in_port_t;typedef uint32_t in_addr_t;
struct in_addr{in_addr_t s_addr;};struct sockaddr_in{__SOCKADDR_COMMON (sin_);in_port_t sin_port;			/* Port number.  */struct in_addr sin_addr;		/* Internet address.  *//* Pad to size of `struct sockaddr'.  */unsigned char sin_zero[sizeof (struct sockaddr)- __SOCKADDR_COMMON_SIZE- sizeof (in_port_t)- sizeof (struct in_addr)];};

可以看到 sockaddr_in结构包含端口号sin_port字段,sin_addr是一个结构体,这个结构体包含了s_addr即IP地址。

第三个字段是填充字段,不需要填充值。

现在解释第一个是什么字段

第一个字段中的__SOCKADDR_COMMON实际上是宏

#define	__SOCKADDR_COMMON(sa_prefix) \sa_family_t sa_prefix##family

 ##表示将sa_prefix与family拼接起来,那么__SOCKADDR_COMMON (sin_);其实就是

sa_family_t sin_family;

这个字段也是需要我们填充的,它也表示协议家族,需要与创建套接字时传入的domain参数保持一致。

而第三个参数是为了让操作系统知道你传入的结构体大小有多大,以便它进行访问。

成功绑定则返回0,否则返回-1。

现在再理解一下绑定,绑定实际上就是把当前这个进程与用户输入的IP地址和端口绑定起来,别人访问这个IP地址,这个端口号,就是在访问这个进程。由此可以发现客户端不需要显式指定要绑定的端口和IP地址,也就是客户端不需要显式调用bind函数,而由操作系统分配某个端口号给该客户端。

关于填充IP地址和端口号,还有一些细节需要补充。

在填充端口号时,并不能确定主机是大端还是小端,绑定端口需要将本地字节序转为网络字节序,只需调用上面的htons即可。

绑定IP地址时,往往用户输入的是类似"127.0.0.1"这种形式,那就需要将这种字符串格式的IP地址转为32位并且转为网络字节序。对于这件事,linux也提供了相应的接口。

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>int inet_aton(const char *cp, struct in_addr *inp);in_addr_t inet_addr(const char *cp);in_addr_t inet_network(const char *cp);char *inet_ntoa(struct in_addr in);struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host);in_addr_t inet_lnaof(struct in_addr in);in_addr_t inet_netof(struct in_addr in);

可用

man inet

指令查看所有接口用法。

 

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

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

相关文章

1720. 解码异或后的数组

解码异或后的数组 题目描述尝试做法 题目描述 未知整数数组 arr 由 n 个非负整数组成。 经编码后变为长度为 n - 1 的另一个整数数组 encoded &#xff0c;其中 encoded[i] arr[i] XOR arr[i 1] 。例如&#xff0c;arr [1,0,2,1] 经编码后得到 encoded [1,2,3] 。 给你编…

了解一下HTTP的短连接和长连接

在 HTTP 协议中&#xff0c;连接的方式主要分为长连接和短连接。这两种连接方式的主要区别在于连接的生命周期和数据传输的效率。理解它们的差异对于优化 Web 应用的性能和资源利用至关重要。以下是 HTTP 长连接和短连接的详细解释。 1. 短连接&#xff08;HTTP/1.0&#xff0…

【WRF模拟】如何查看 WPS 的输入静态地理数据(二进制格式)?

查看 WPS 的输入静态地理数据方法总结 方法 1:使用 gdal_translate 将二进制数据转换为 GeoTIFFgdal_translate 工具概述使用 gdal_translate 将二进制数据转换为 GeoTIFF方法 2:使用 ncdump 查看 geo_em.dXX.nc方法 3:使用 Python xarray + matplotlib 可视化 geo_em.dXX.n…

Mybatis语法bug

select * from appointment where status ‘ACCEPTED’ and expire_time< now() idea显示now&#xff08;&#xff09;这里一直报错&#xff1a; 应为标记名称 应为 Deepseek: 根据您的代码和报错信息分析&#xff0c;这是一个 MyBatis XML 文件中的 SQL 语法问题。具体原…

DeepSeek本机部署(基于Ollama和Docker管理)

目录 一、ollama 与 docker 简介 &#xff08;一&#xff09;ollama(Ollama) &#xff08;二&#xff09;docker 二、利用 ollama 和 docker 配置 deepseek-r1 的准备工作 &#xff08;一&#xff09;硬件需求 &#xff08;二&#xff09;软件安装 三、配置 deepseek-r1…

小程序 wxml 语法 —— 39 简单双向数据绑定

在 WXML 中&#xff0c;普通属性的绑定是单向的&#xff0c;比如 <input value"{{ value }}" />&#xff0c;当数据发生改变时&#xff0c;页面也会随之发生变化&#xff0c;但是当用户在输入框中输入最新内容&#xff0c;最新内容并不会同步给 value 数据&…

Linux第一次练习

1、找到你的Linux系统上的不同颜色的文件&#xff0c;每一种颜色的文件找到3个以上 蓝色&#xff1a; 白色&#xff1a; 绿色&#xff1a; 红色&#xff1a; 黄色&#xff1a; 2、设置一个ping的别名永久生效&#xff0c;设置一个ymd的别名date %F永久生效

《C#上位机开发从门外到门内》2-2:I2C总线协议及其应用详解

文章目录 一、引言二、I2C总线协议的基本概念三、I2C通信机制3.1 硬件结构与基本原理3.2 信号的起始与终止3.3 数据传输格式及时序3.4 时钟同步与时钟伸展 四、设备寻址与数据传输4.1 I2C设备寻址方式4.2 地址冲突及解决方法4.3 数据传输过程中的确认机制4.4 I2C数据帧结构与传…

Trae IDE:解锁 AI 驱动的高效编程体验

Trae 介绍 Trae 是字节跳动推出的一款面向开发者的 AI 驱动的集成开发环境&#xff08;IDE&#xff09;&#xff0c;于 2024 年 1 月 19 日在新加坡正式发布海外版&#xff0c;2025 年 3 月 3 日发布国内版。海外版由字节跳动旗下的 SPRING&#xff08;SG&#xff09;PTE.LTD.…

玩转python:通俗易懂掌握高级数据结构:collections模块之namedtuple

引言 namedtuple是Python中collections模块提供的一个强大工具&#xff0c;用于创建具有字段名的元组。它不仅具备元组的不可变性&#xff0c;还能通过字段名访问元素&#xff0c;极大地提高了代码的可读性和可维护性。本文将详细介绍namedtuple的关键用法和特性&#xff0c;并…

我的创作纪念日:730天的技术写作之旅

我的创作纪念日&#xff1a;730天的技术写作之旅 机缘 从一篇案例分析开始 2023年3月13日&#xff0c;我写下了第一篇技术博客《软考高级-系统分析师-案例分析-系统维护与设计模式》。那时的初心很简单&#xff1a; 沉淀实战经验——在备考软考系统分析师时&#xff0c;发现…

使用 Arduino 和 ESP8266 Wi-Fi 模块发送电子邮件

使用 Arduino Uno 和 ESP8266 Wi-Fi 模块发送电子邮件 我们正在迈向物联网 (IoT) 世界。这项技术在电子和嵌入式系统中起着非常重要的作用。从任何微控制器或嵌入式系统发送电子邮件都是非常基本的事情,这在 IoT 中是必需的。因此,在本文中,我们将学习“如何使用 Wi-Fi 和…

golang算法二叉树对称平衡右视图

100. 相同的树 给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例 1&#xff1a; 输入&#xff1a;p [1,2,3], q [1,2,3] 输出&#xff1a…

c++介绍智能指针 十二(1)

普通指针&#xff1a;指向内存区域的地址变量。使用普通指针容易出现一些程序错误。 如果一个指针所指向的内存区域是动态分配的&#xff0c;那么这个指针变量离开了所在的作用域&#xff0c;这块内存也不会自动销毁。动态内存不进行释放就会导致内存泄露。如果一个指针指向已…

亚马逊COSMO算法解读:新搜索时代的流量分配与DeepBI AI驱动的智能优化策略

亚马逊COSMO算法的推出&#xff0c;标志着其搜索和推荐系统进入了智能化、个性化的新阶段。该算法通过分析用户购物习惯、搜索历史、浏览行为等数据&#xff0c;为买家提供精准推荐&#xff0c;同时对卖家的运营策略提出了更高的要求。在这一背景下&#xff0c;AI驱动的DeepBI能…

C++编译问题——1模板函数的实现必须在头文件中

今天编译数据结构时&#xff0c;遇见一个编译错误 假设你有一个头文件 SeqList.h 和一个源文件 SeqList.cpp。 SeqList.h #ifndef SEQLIST_H #define SEQLIST_H#include <stdexcept> #include <iostream>template<typename T> class SeqList { private:sta…

安卓实现魔改版 CRC32 算法

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 关于 CRC32 算法介绍可以参考这篇文章&#xff1a;常用加解密算法介绍 标准 CRC32 算法 创建 crc32.cpp&#xff0c;使用 C 实现标准 CRC32 算法 #include …

OneHot编码与OrdinalEncoder编码的区别与应用解析

OneHot编码和OrdinalEncoder编码是两种常见的类别特征编码方式&#xff0c;它们的主要目的是将类别数据转换为数值数据&#xff0c;以便机器学习算法能够处理。下面是对这两种编码方式的详细解释和比较&#xff1a; 一、OneHot编码 1. 定义&#xff1a; OneHot编码是一种将每…

python离线安装

Python Releases for Windows | Python.org 下载包地址widows一般是64bit的包 下载完成后双击&#xff0c;在弹出的首个页面会看到下面的图 第一步&#xff1a;建议手动安装 第二步&#xff1a;一定要勾选把版本加入到Path路径 然后就是无脑下一步&#xff0c;到这一步就可…

Web开发-PHP应用文件操作安全上传下载任意读取删除目录遍历文件包含

知识点&#xff1a; 1、安全开发-原生PHP-文件安全操作 2、安全开发-原生PHP-上传读取删除包含等 3、安全开发-原生PHP-代码审计文件安全 一、演示案例-WEB开发-文件安全-上传下载读取 文件上传 $_FILES&#xff1a;PHP中一个预定义的超全局变量&#xff0c;用于在上传文件时…