Linux--Socket套接字编程

news2024/11/22 21:05:48

Socket编程

Socket编程是一种在网络中不同计算机之间实现数据交换的编程方式。它允许程序创建网络连接,并通过这些连接来发送和接收数据。Socket编程是网络编程的基础,广泛应用于客户端-服务器(C/S)架构中。

要实现双方通信,就需要对应的地址,那如何找到对方的网络地址呢

IP地址和端口号

  • IP地址用于标识网络中的每一台设备
  • 端口号用于标识设备上的特定应用程序或服务(进程)
  • 端口号是一个 2 字节 16 位的整数;
  • 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来
    处理;
  • 一个端口号只能被一个进程占用
  • 端口号是传输层协议的内容
  • 0 - 1023: 知名端口号, HTTP, FTP, SSH 等这些广为使用的应用层协议, 他们的
    端口号都是固定的.
  • 1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号, 就是由操作
    系统从这个范围分配的.

在这里插入图片描述
所以在网络通信中,可以通过IP地址锁定对应的主机,再通过端口号锁定对应主机上的应用程序或服务;
IP地址+端口号也成唯一标识的网络地址
Socket也就是将IP和port套在一起,完成网络间的通信;

进程ID和端口号

  • 进程ID是操作系统分配给每个正在运行的进程的唯一标识符。通过PID,操作系统可以跟踪和管理每个进程。
  • 端口号是一个逻辑概念,用于区分同一台计算机上不同应用程序或服务所使用的网络通信端口。每个端口号都对应着一个特定的服务或应用程序的实例。
  • 区别:进程ID用于操作系统内部管理和区分不同的进程,而端口号则用于网络通信中区分不同的应用程序或服务
  • 一个进程可以绑定多个端口号; 但是一个端口号不能被多个进程绑定

Socket的文件描述符

套接字(Socket)是一种在计算机网络中进行数据交换的端点。在UNIX和类UNIX系统中(如Linux和macOS),套接字被实现为文件描述符,这使得套接字可以像文件一样被打开、读写和关闭。文件描述符是一个非负整数,它是一个索引值,指向内核中每个进程打开文件的记录表。对于套接字而言,这个“文件”实际上是一个网络通信的端点

网络字节序

网络字节序,也称为大端字节序(Big-Endian),是指在网络通信协议中规定的字节序
它规定整数的高位字节必须先传输到网络上,即高位字节在前,低位字节在后。
主机字节序是指特定主机或处理器所采用的字节序。它取决于主机的硬件架构,可能是大端序或小端序(Little-Endian)。

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

#include <arpa/inet.h>
uint32_t htonl(uint32 t hostlong);
uint16_t htons(uintl6 t hostshort);
uint32_t ntohl(uint32tnetlong);
uint16_t ntohs(uintl6 ttnetshort);

Socket编程常见API

Socket是一个网络编程接口,是TCP/IP网络的API,它定义了一种方式,使应用程序可以通过网络与其他应用程序进行通信

socket()

#include <sys/socket.h>
int socket(int domain, int type, int protocol);

socket函数是用于创建一个新的套接字的系统调用。套接字(Socket)是网络通信的基本单元,它提供了一种在应用程序之间(可能位于同一台机器或不同的机器上)进行通信的方式;

参数说明:

  • domain:指定协议族。常见的协议族有AF_INET(IPv4)、AF_INET6(IPv6)、AF_UNIX(本地套接字,用于同一机器上的进程间通信)等。
  • type:指定套接字的类型。常见的套接字类型有SOCK_STREAM(流套接字,提供可靠的、面向连接的通信,如TCP)、SOCK_DGRAM(数据报套接字,提供不可靠的、无连接的通信,如UDP)、SOCK_RAW(原始套接字,允许应用程序直接操作网络层协议)等。
  • protocol:指定协议。在大多数情况下,该参数可以设置为0,以选择协议族中默认的协议。

返回值:

  • 如果成功,socket函数返回一个非负整数,即新创建的套接字的文件描述符
  • 如果失败,返回-1,并设置全局变量errno以指示错误。

bind()

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

bind函数通常与网络编程相关,特别是在使用套接字(sockets)进行通信时,
bind函数用于将套接字与特定的本地地址和端口号绑定,从而确定套接字在网络上的标识

参数说明:

  • sockfd:套接字描述符,通常是通过socket函数创建的。
  • addr:指向struct sockaddr结构体的指针,该结构体中包含了要绑定的地址和端口信息。通常,对于IPv4地址,会使用struct sockaddr_in,而对于IPv6地址,则使用struct sockaddr_in6。这些结构体都需要强制类型转换为struct sockaddr*来传递给bind函数。
  • addrlen:addr结构体的大小。

返回值:
如果成功,bind函数返回0。
如果失败,返回-1,并设置全局变量errno以指示错误。

sockaddr_in结构体

struct in_addr
{
	uint32_t s_addr; /* IPv4 地址 */
};
struct sockaddr_in 
{
	shortsin_family;/*地址家族,AF_INET */
	unsigned shortsin_port;/*端口号,网络字节序*/
	struct in_addr sin_addr;/* IPv4 地址*/
	char sin_zero[8]/*未使用的字节,用零填充以保持结构大小与sockaddr相同3;
};

sockaddr_in是用于IPv4地址的套接字地址结构。它包含在sys/socket.h头文件中,并且是sockaddr结构的特定于IPv4的版本。当你需要在网络编程中处理IPv4地址时,你会经常与这个结构打交道。

成员变量:

  • sin_family:这是一个地址家族标识符,对于IPv4 来说,它通常被设置为AF_INET
  • sin_port:这是一个 16 位的端口号,它使用网络字节序(大端字节序)。在将端口号赋值给 sin_port 之前,你需要使用 htons() 函数(host to networkshort)来将主机字节序转换为网络字节序
  • sin_addr:这是一个 in_addr 结构,包含一个 32 位的IPv4 地址。在赋值之前,你可能需要将点分十进制表示法(如"192.168.1.1")转换为 32 位整数。这通常通过 inet _pton() 函数(presentation to network)来完成。
  • sin_zero:这是一个填充字段,用于确保sockaddr_in 结构的大小与通用的 sockaddr 结构相同。在实际使用中,这个字段通常被忽略。

recvfrom()

使用套接字(sockets)进行UDP通信时,这个函数用于从指定的套接字接收数据,并返回发送数据的地址
与TCP使用的 recv() 函数不同,recvfrom() 特别适用于无连接的UDP协议,因为它需要知道数据是从哪个地址发送来的。

#include <sys/socket.h>  
  
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,  
                 struct sockaddr *src_addr, socklen_t *addrlen);

参数说明:

  • sockfd:套接字文件描述符,标识了一个打开的套接字。
  • buf:指向一个缓冲区的指针,用于存放接收到的数据。
  • len:指定了buf的大小,即可以接收的最大字节数。
  • flags:通常设置为0,但在某些特殊情况下可以用来控制函数的行为(如MSG_DONTWAIT标志,用于非阻塞套接字)。
  • src_addr:一个指向sockaddr结构的指针,该结构在调用后会被填充为发送数据的源地址。如果调用者不关心源地址,这个参数可以设置为NULL。
  • addrlen:是一个指向socklen_t的指针,在调用前应该包含src_addr指向的sockaddr结构的大小,在调用后,这个值会被更新为实际使用的结构大小。

返回值

  • 成功时,recvfrom() 返回接收到的字节数。
  • 如果连接被对方正常关闭,则返回0。
  • 如果发生错误,则返回-1,并设置相应的errno以指示错误类型

sendto()

用于UDP协议,允许开发者将数据从指定的套接字发送到对方主机,同时指定目的地址

#include <sys/types.h>  
#include <sys/socket.h>  
  
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,  
               const struct sockaddr *dest_addr, socklen_t addrlen);

参数说明

  • sockfd:套接字文件描述符,标识了一个打开的套接字。
  • buf:指向要发送数据的缓冲区的指针。
  • len:要发送的数据的字节数。
  • flags:指定发送数据的方式,通常设置为0即可。但可以改变flags来改变sendto()发送的形式。
  • dest_addr:一个指向目的地址结构体的指针,包括目的IP地址和端口号等信息。
  • addrlen:表示目的地址结构体的长度。

返回值

  • 成功时,sendto() 返回实际发送的字节数。
  • 如果发生错误,则返回-1,并设置相应的errno以指示错误类型。

recv()

recv() 函数是网络编程中用于接收数据的函数,它主要用于TCP协议;
与recvfrom()不同,recv()不需要指定数据的来源地址,因为TCP是面向连接的协议,每个套接字(socket)都直接关联到一个特定的连接,所以接收的数据自然就是来自该连接的另一端

#include <sys/types.h>  
#include <sys/socket.h>  
  
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

参数说明

  • sockfd:套接字文件描述符,标识了一个打开的套接字。
  • buf:指向一个缓冲区的指针,用于存放接收到的数据。
  • len:指定了buf的大小,即可以接收的最大字节数。
  • flags:指定接收数据的方式,通常设置为0即可。但可以改变flags来改变recv()的行为,例如使用MSG_DONTWAIT标志进行非阻塞接收。

返回值

  • 成功时,recv() 返回接收到的字节数。
  • 如果连接被对方正常关闭,并且已经接收到了对方发送的FIN包,则返回0。
  • 如果发生错误,则返回-1,并设置相应的errno以指示错误类型。

send()

send() 函数是网络编程中用于发送数据的函数,它主要用于TCP协议。
与sendto()不同,send()不需要指定目的地址,因为TCP是面向连接的协议,每个套接字(socket)都直接关联到一个特定的连接,所以发送的数据自然就是发送到该连接的另一端

#include <sys/types.h>  
#include <sys/socket.h>  
  
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

参数说明

  • sockfd:套接字文件描述符,标识了一个打开的套接字。
  • buf:指向要发送数据的缓冲区的指针。
  • len:要发送的数据的字节数。
  • flags:指定发送数据的方式,通常设置为0即可。但可以改变flags来改变send()的行为,例如使用MSG_DONTWAIT标志进行非阻塞发送。

返回值

  • 成功时,send() 返回实际发送的字节数。这可能与请求发送的字节数相同,也可能不同(特别是在非阻塞模式下)。
  • 如果发生错误,则返回-1,并设置相应的errno以指示错误类型。

listen()

listen() 函数是在网络编程将套接字(socket)设置为监听状态,等待客户端的连接请求。常用于TCP协议。

#include <sys/socket.h>  
  
int listen(int sockfd, int backlog);

参数说明

  • sockfd:套接字文件描述符,这是之前通过 socket() 函数创建的套接字,并且已经通过 bind() 函数绑定了特定的IP地址和端口号。
  • backlog:这个参数指定了操作系统可以挂起(即等待处理)的连接请求的最大数量。当超过这个数量时,新的连接请求可能会被拒绝。需要注意的是,这个值并不直接对应于队列中的最大连接数,而是操作系统用来处理并发连接请求的一个参数。

返回值

  • 监听成功时返回0
  • 监听失败时返回-1

函数作用

  • 设置监听状态:listen() 函数将 sockfd 指定的套接字设置为监听状态,使其能够接收来自客户端的连接请求。
  • 维护请求队列:操作系统会为处于监听状态的套接字维护两个队列:
    未完成连接队列(SYN_RCVD):这个队列用于存放那些已经接收到客户端的SYN包,但尚未完成三次握手过程的连接请求。
  • 已完成连接队列(ESTABLISHED):当三次握手过程完成后,连接请求会被移动到这个队列中,等待服务器端的 accept() 函数来接受。
  • 控制并发连接:通过 backlog 参数,listen() 函数帮助服务器控制可以同时处理的并发连接数量,从而避免系统资源的过度消耗。

accept()

accept() 函数: 接受一个客户端的连接请求,并返回一个新的套接字(socket)描述符,用于与客户端进行后续的通信。常用于TCP协议。

#include <sys/types.h>  
#include <sys/socket.h>  
  
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数说明

  • sockfd:这是一个套接字描述符,用于指定服务器端的监听套接字。这个套接字是之前通过- socket()函数创建的,并且已经通过bind()函数绑定了特定的IP地址和端口号,还通过listen()函数设置为监听状态。
  • addr:这是一个指向sockaddr结构的指针,用于存储连接请求的客户端的地址信息。如果调用者不关心客户端的地址信息,可以将此参数设置为NULL。但通常,为了后续与客户端的通信,我们需要知道客户端的地址信息。
  • addrlen:这是一个指向socklen_t变量的指针,该变量在调用前应该被设置为addr所指向的sockaddr结构的大小。在调用accept()后,该变量会被更新为实际存储在addr中的地址信息的大小。

返回值

  • 成功时,accept()函数返回一个非负的整数,即新创建的套接字描述符。
  • 失败时,返回-1,并设置errno以指示错误原因。

函数作用

  • 接受连接请求:当服务器端的监听套接字收到一个客户端的连接请求时,accept()函数会被调用以接受这个请求。如果监听套接字当前没有连接请求,accept()函数会根据套接字的阻塞/非阻塞属性来决定是立即返回错误还是等待直到有连接请求到来
  • 创建新套接字:一旦accept()函数接受了一个连接请求,它就会为这次连接创建一个新的套接字描述符,并返回这个描述符给调用者。这个新的套接字描述符用于后续的通信操作,如发送和接收数据
  • 返回客户端信息(如果addr不为NULL):accept()函数还会将连接请求的客户端地址信息存储在addr所指向的sockaddr结构中,并通过addrlen参数返回实际存储的字节数。这样,服务器就可以知道是哪个客户端发起的连接请求。

connect()

connect() 函数用于客户端程序,以建立与服务器之间的连接。常用于TCP协议。

#include <sys/types.h>  
#include <sys/socket.h>  
  
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数说明

  • sockfd:这是一个套接字描述符,用于指定要发起连接的客户端套接字。这个套接字是之前通过socket()函数创建的。
  • addr:这是一个指向sockaddr结构的指针,包含了目标服务器的地址信息,包括IP地址和端口号。在实际编程中,由于sockaddr是一个通用的地址结构,通常会使用其特定类型(如sockaddr_in对于IPv4)来方便地设置地址和端口。
  • addrlen:这个参数指定了addr所指向的地址结构的大小,通常是通过sizeof()运算符来获取的,如sizeof(struct sockaddr_in)。

返回值

  • 如果连接成功,函数返回0;
  • 如果连接失败,则返回-1,并设置全局变量errno以指示错误原因。

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

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

相关文章

【扩散模型(六)】Stable Diffusion 3 diffusers 源码详解1-推理代码-文本处理部分

系列文章目录 【扩散模型&#xff08;一&#xff09;】中介绍了 Stable Diffusion 可以被理解为重建分支&#xff08;reconstruction branch&#xff09;和条件分支&#xff08;condition branch&#xff09;【扩散模型&#xff08;二&#xff09;】IP-Adapter 从条件分支的视…

基于python的去除图像内部填充

1 代码功能 该代码实现了一个图像处理的功能&#xff0c;具体来说是去除图像内部填充&#xff08;或更准确地说&#xff0c;是提取并显示图像中轮廓的外围区域&#xff0c;而忽略内部填充&#xff09;。以下是该功能的详细步骤&#xff1a; 读取图像&#xff1a;使用cv2.imread…

Hadoop-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; HadoopHDFSMapReduceHiveFlumeSqoopZookeeperHBaseRedis 章节内容 上一节我们完成了&#xff1a; HBase …

机器学习-18-统计学与机器学习中回归的区别以及统计学基础知识

参考通透!一万字的统计学知识大梳理 参考3万字长文!手把手教你学会用Python实现统计学 参考统计学的回归和机器学习中的回归有什么差别? 1 研究对象 一维:就是当前摆在我们面前的“一组”,“一批数据。这里我们会用到统计学的知识去研究这类对象。 二维:就是研究某个“事…

【系统架构设计】数据库系统(三)

数据库系统&#xff08;三&#xff09; 数据库模式与范式数据库设计备份与恢复分布式数据库系统分布式数据库的概念特点分类目标 分布式数据库的架构分布式数据库系统与并行数据库系统 数据仓库数据挖掘NoSQL大数据 数据库模式与范式 数据库设计 备份与恢复 分布式数据库系统…

生活中生智慧

【 圣人多过 小人无过 】 觉得自己做得不够才能做得更好&#xff0c;互相成全&#xff1b;反求诸己是致良知的第一步&#xff1b;有苦难才能超越自己&#xff0c;开胸怀和智慧&#xff1b;不浪费任何一次困苦&#xff0c;危机中寻找智慧&#xff0c;成长自己。 把困苦当作当下…

自动驾驶三维车道线检测系列—LATR: 3D Lane Detection from Monocular Images with Transformer

文章目录 1. 概述2. 背景介绍3. 方法3.1 整体结构3.2 车道感知查询生成器3.3 动态3D地面位置嵌入3.4 预测头和损失 4. 实验评测4.1 数据集和评估指标4.2 实验设置4.3 主要结果 5. 讨论和总结 1. 概述 3D 车道线检测是自动驾驶中的一个基础但具有挑战性的任务。最近的进展主要依…

【NetTopologySuite类库】GeometryFixer几何自动修复,解决几何自相交等问题

介绍 NetTopologySuite 2.x 提供了GeometryFixer类&#xff0c;该类能够将几何体修复为有效几何体&#xff0c;同时尽可能保留输入的形状和位置。几何的IsValid属性&#xff0c;反映了几何是否是有效的。 输入的几何图形始终会被处理&#xff0c;因此即使是有效的输入也可能会…

特征工程方法总结

方法有以下这些 首先看数据有没有重复值、缺失值情况 离散&#xff1a;独热 连续变量&#xff1a;离散化&#xff08;也成为分箱&#xff09; 作用&#xff1a;1.消除异常值影响 2.引入非线性因素&#xff0c;提升模型表现能力 3.缺点是会损失一些信息 怎么分&#xff1a;…

pdf太大了怎么变小 pdf太大了如何变小一点

在数字化时代&#xff0c;pdf文件已成为工作与学习的重要工具。然而&#xff0c;有时我们可能会遇到pdf文件过大的问题&#xff0c;这会导致传输困难或者存储不便。别担心&#xff0c;下面我将为你介绍一些实用的技巧和工具&#xff0c;帮助你轻松减小pdf文件的大小。 方法一、…

docker的学习(一):docker的基本概念和命令

简介 docker的学习&#xff0c;基本概念&#xff0c;以及镜像命令和容器命令的使用 docker docker的基本概念 一次镜像&#xff0c;处处运行。 在部署程序的过程中&#xff0c;往往是很繁琐的&#xff0c;要保证运行的环境&#xff0c;软件的版本&#xff0c;配置文件&…

SQLite数据库在Android中的使用

目录 一&#xff0c;SQLite简介 二&#xff0c;SQLIte在Android中的使用 1&#xff0c;打开或者创建数据库 2&#xff0c;创建表 3&#xff0c;插入数据 4&#xff0c;删除数据 5&#xff0c;修改数据 6&#xff0c;查询数据 三&#xff0c;SQLiteOpenHelper类 四&…

信弘智能与图为科技共探科技合作新蓝图

本期导读 近日&#xff0c;图为信息科技&#xff08;深圳&#xff09;有限公司迎来上海信弘智能科技有限公司代表的到访&#xff0c;双方共同探讨英伟达生态系统在人工智能领域的发展。 在科技日新月异的今天&#xff0c;跨界合作与技术交流成为了推动行业发展的重要驱动。7月…

使用JWT双令牌机制进行接口请求鉴权

在前后端分离的开发过程中&#xff0c;前端发起请求&#xff0c;调用后端接口&#xff0c;后端在接收请求时&#xff0c;首先需要对收到的请求鉴权&#xff0c;在这种情况先我们可以采用JWT机制来鉴权。 JWT有两种机制&#xff0c;单令牌机制和双令牌机制。 单令牌机制服务端…

JAVA 异步编程(线程安全)二

1、线程安全 线程安全是指你的代码所在的进程中有多个线程同时运行&#xff0c;而这些线程可能会同时运行这段代码&#xff0c;如果每次运行的代码结果和单线程运行的结果是一样的&#xff0c;且其他变量的值和预期的也是一样的&#xff0c;那么就是线程安全的。 一个类或者程序…

Linux驱动开发-06蜂鸣器和多组GPIO控制

一、控制蜂鸣器 1.1 控制原理 我们可以看到SNVS_TAMPER1是这个端口在控制着蜂鸣器,同时这是一个PNP型的三极管,在端口输出为低电平时,蜂鸣器响,在高电平时,蜂鸣器不响 1.2 在Linux中端口号的控制 gpiochipX:当前SoC所包含的GPIO控制器,我们知道I.MX6UL/I.MX6ULL一共包…

整顿职场?安全体系建设

本文由 ChatMoney团队出品 00后整顿职场&#xff0c;职场到底怎么了&#xff1f;无压力、无忧虑的00后可以直接开整&#xff0c;那绝大部分打工人寒窗苦读、闯过高考&#xff0c;艰辛毕业&#xff0c;几轮面试杀入职场&#xff0c;结婚买房、上有老下有小&#xff0c;就活该再被…

怎么剪辑音频文件?4款适合新的音频剪辑软件

是谁还不会音频剪辑&#xff1f;无论是个人音乐爱好者&#xff0c;还是专业音频工作者&#xff0c;我们都希望能找到一款操作简便、功能强大且稳定可靠的音频剪辑工具。今天&#xff0c;我就要为大家带来四款热门音频剪辑软件的体验感分享。 一、福昕音频剪辑 福昕音频剪辑是…

JUnit 单元测试

JUnit 测试是程序员测试&#xff0c;就是白盒测试&#xff0c;可以让程序员知道被测试的软件如何 &#xff08;How&#xff09;完成功能和完成什么样&#xff08;What&#xff09;的功能。 下载junit-4.12和hamcrest-core-1.3依赖包 相关链接 junit-4.12&#xff1a;Central …

【JavaScript 算法】最长公共子序列:字符串问题的经典解法

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、算法原理状态转移方程初始条件 二、算法实现注释说明&#xff1a; 三、应用场景四、总结 最长公共子序列&#xff08;Longest Common Subsequence&#xff0c;LCS&#xff09;是字符串处理中的经典问题。给定两个字符串…