SOCKET编程(3):相关结构体与函数

相关结构体与函数

sockaddr、sockaddr_in结构体

sockaddr和sockaddr_in详解

struct sockaddr共16字节,协议族(family)占2字节,IP地址和端口号在sa_data字符数组中

/* Structure describing a generic socket address.  */
struct sockaddr
{
  __SOCKADDR_COMMON(sa_); /* Common data: address family and length.  */
  char sa_data[14];       /* Address data.  */
};

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

struct sockaddr_in更细致地划分了协议族、端口号和IP地址,其中IP地址定义了新的结构体struct in_addr该结构体中宏定义了uint32_t类型的变量,sin_zero字符数组存在的意义是为了使struct sockaddr_instruct sockaddr 大小相等,便于进行强制类型转换(与bind()等函数的参数有关)

/* Structure describing an Internet socket address.  */
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)];
};

/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
{
  in_addr_t s_addr;
};

总结

  1. 二者长度一样,都是16个字节,即占用的内存大小是一致的,因此可以互相转化。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr
  2. sockaddr常用于bind、connect、recvfrom、sendto等函数的参数,指明地址信息,是一种通用的套接字地址
  3. sockaddr_in 是internet环境下套接字的地址形式
  4. 在网络编程中我们会对sockaddr_in结构体进行操作,使用sockaddr_in来建立所需的信息,最后使用类型转化
  5. 一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数:sockaddr_in用于socket定义和赋值;sockaddr用于函数参数

socket()函数

socket函数用于创建一个新的socket,也就是向系统申清一个socket资源

socket函数用户客户端和服务端

int socket(int domain, int type, int protocol);

domain:协议域,又称协议族(family)。常用的协议族有AF INET、AF INET6、AF LOCAL(或称AF UNIX,Unix域Socket)、AF ROUTE等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址

type:指定socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK RAW、SOCK_PACKET、SOCK_SEQPACKET等。流式socket(SOCK_STREAM)是一种面向连接的socket,针对于面向连接的TCP服务应用。数据报式socket(SOCK_DGRAM)是一种无连接的socket,对应于无连接的UDP服务应用

protocol:指定协议。常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议

💡 第一个参数只能填AF INET,第二个参数只能填SOCK STREAM,第三个参数只填0

除非系统资料耗尽,socket函数一般不会返回失败

返回值:成功则返回一个socket,失败返回-1,错误原因存于errno中

💡 “资源耗尽”即Linux对打开文件数的限制,见2022-06-10笔记

// 第1步:创建服务端的socket
int listenfd;
for (int i = 0; i < 2000; ++i)
{
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket");
        return -1;
    }
    cout << "sock id:" << listenfd << endl;
}
sock id:1012
sock id:1013
sock id:1014
sock id:1015
sock id:1016
sock id:1017
sock id:1018
sock id:1019
sock id:1020
sock id:1021
sock id:1022
sock id:1023
socket: Too many open files

inet_addr() 和inet_ntoa()函数

使用socket进行通信的时候,我们需要指定三个元素:通信域(地址族)、IP地址、端口号,这三个元素由SOCKADDR_IN结构体定义

为了简化编程一般将IP地址设置为INADDR_ANY,如果需要使用特定的IP地址则需要使用inet_addr()** 和**inet_ntoa()函数

inet_addr()inet_ntoa()完成字符串和in_addr结构体的互换

inet_addr()函数参数cp代表点分十进制的IP地址,如1.2.3.4,返回值为in_addr_t 类型

/* Convert Internet host address from numbers-and-dots notation in CP
   into binary data in network byte order.  */
extern in_addr_t inet_addr (const char *__cp) __THROW;

inet_ntoa() 函数输入为in_addr结构体而输出为字符串

/* Convert Internet number in IN to ASCII representation.  The return value
   is a pointer to an internal array containing the string.  */
extern char *inet_ntoa (struct in_addr __in) __THROW;

hostent结构体

hostent实例详解

/* Description of data base entry for a single host.  */
struct hostent
{
  char *h_name;			/* Official name of host.  */
  char **h_aliases;		/* Alias list.  */
  int h_addrtype;		/* Host address type.  */
  int h_length;			/* Length of address.  */
  char **h_addr_list;		/* List of addresses from name server.  */
#ifdef __USE_MISC
# define	h_addr	h_addr_list[0] /* Address, for backward compatibility.*/
#endif
};
struct hostent
	{
		char *h_name;         //正式主机名
		char **h_aliases;     //主机别名
		int h_addrtype;       //主机IP地址类型:IPV4-AF_INET
		int h_length;		      //主机IP地址字节长度,对于IPv4是四字节,即32位
		char **h_addr_list;	  //主机的IP地址列表
	};
	
	#define h_addr h_addr_list[0]   //保存的是IP地址
  • h_name:官方域名(Official domain name)。官方域名代表某一主页,但实际上一些著名公司的域名并未用官方域名注册
  • h_aliases:别名,可以通过多个域名访问同一主机。同一 IP 地址可以绑定多个域名,因此除了当前域名还可以指定其他域名
  • h_addrtype:gethostbyname() 不仅支持 IPv4,还支持 IPv6,可以通过此成员获取IP地址的地址族(地址类型)信息,IPv4 对应 AF_INET,IPv6 对应 AF_INET6
  • h_length:保存IP地址长度。IPv4 的长度为 4 个字节,IPv6 的长度为 16 个字节
  • h_addr_list:这是最重要的成员。通过该成员以整数形式保存域名对应的 IP 地址。对于用户较多的服务器,可能会分配多个 IP 地址给同一域名,利用多个服务器进行均衡负载

在这里插入图片描述

在实际的应用中,一台服务器往往有好几个IP地址,而域名只有一个,这样设计的好处是,可以使系统分布设计,提升服务器的稳定性和抗灾难能力

一般对服务器的访问,则是先经过DNS(Domain Name System)服务器,DNS通过均衡设计,返回合适的IP与客户端进行交互,避免客户端只连接一个IP,导致网络拥堵

gethostbyname()函数

gethostbyname()函数:通过域名获取IP地址

gethostbyname()函数详解

客户端中直接使用IP地址会有很大的弊端,一旦IP地址变化(IP地址会经常变动),客户端软件就会出现错误
而使用域名会方便很多,注册后的域名只要每年续费就永远属于自己的,更换IP地址时修改域名解析即可,不会影响软件的正常使用

域名仅仅是 IP 地址的一个助记符,目的是方便记忆,通过域名并不能找到目标计算机,通信之前必须要将域名转换成 IP 地址

gethostbyname() 函数可以完成这种转换

/* Return entry from host data base for host with NAME.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern struct hostent *gethostbyname (const char *__name);

bind()函数

服务端用于将把用于通信的地址和端口绑定到socket上

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

sockfd:需要绑定的socket

addr:存放了服务端用于通信的地址和端口

addrlen:表示addr结构体的大小

返回值:成功则返回0,失败返回-1,错误原因存于errno中

如果绑定的地址错误,或端口已被占用,bind函数一定会报错,否则一般不会返回错误

💡 注意第二个参数为sockaddr结构体指针

在这里插入图片描述

listen()函数

listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程

在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接

/* Prepare to accept connections on socket FD.
   N connection requests will be queued before further requests are refused.
   Returns 0 on success, -1 for errors.  */
extern int listen (int __fd, int __n) __THROW;

_fd:服务端的socket,标识绑定的,未连接的套接字的描述符

-n:挂起的连接队列的最大长度

  • 比如有100个用户链接请求,但是系统一次只能处理20个,那么剩下的80个不能不理人家,所以系统就创建个队列记录这些暂时不能处理,一会儿处理的连接请求,依先后顺序处理,那这个队列到底多大?就是这个参数设置,比如2,那么就允许两个新链接排队。这个不能无限大,那内存就不够了
  • 可以手动设置这个参数,但是别太大
  • 我们一般填写这个参数为SOMAXCONN ,让系统自动选择最合适的个数

connect()函数

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

参数:
第一个参数:int sockdf:
		    socket文件描述符
第二个参数: const struct sockaddr *addr:
			传入参数,指定服务器端地址信息,含IP地址和端口号
第三个参数:socklen_t addrlen:
			传入参数,传入sizeof(addr)大小
返回值:
	成功: 0
	失败:-1,设置errno

当客户端调用 connect()函数之后,发生一下情况之一才会返回(完成函数调用)

  • 服务器端接收连接请求
  • 发生断网的异常情况而终端连接请求

需要注意的是,所谓的“接收连接”并不意味着服务器调用 accept()函数,其实是服务器端把连接请求信息记录到等待队列,因此 connect()函数返回后并不进行数据交换,而是要等服务器端 accept 之后才能进行数据交换(read、write)

客户端端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址

accept()函数

socket的accept函数解析

socket中accept()函数的理解

/* Await a connection on socket FD.
   When a connection arrives, open a new socket to communicate with it,
   set *ADDR (which is *ADDR_LEN bytes long) to the address of the connecting
   peer and *ADDR_LEN to the address's actual length, and return the
   new socket's descriptor, or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int accept (int __fd, __SOCKADDR_ARG __addr,
		   socklen_t *__restrict __addr_len);

在这里插入图片描述

send()函数

send函数用于把数据通过socket发送给对端

不论是客户端还是服务端,应用程序都用send函数来向TCP连接的另一端发送数据

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • sockfd为已建立好连接的socket
  • buf为需要发送的数据的内存地址,可以是C语言基本数据类型变量的地址,也可以数组、结构体、字符串,内存中有什么就发送什么
  • len需要发送的数据的长度,为buf中有效数据的长度
  • flags填0,其他数值意义不大
  • 函数返回已发送的字符数,出错时返回-1,错误信息errno被标记
  • 注意,就算是网络断开,或socket已被对端关闭,send函数不会立即报错,要过几秒才会报错
  • 如果send函数返回的错误(<=0),表示通信链路已不可用

recv()函数

recv函数用于接收对端通过socket发送过来的数据

不论是客户端还是服务端,应用程序都用recv函数接收来自TCP连接的另一端发送过来数据

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

参数信息同send()函数

函数返回已接收的字符数,出错时返回-1,失败时不会设置errno的值

  • 如果socket的对端没有发送数据,recv函数就会等待
  • 如果对端发送了数据,函数返回接收到的字符数
  • 出错时返回-1,如果socket被对端关闭,返回值为0
  • 如果recv函数返回的错误(<=0),表示通信通道已不可用

💡 数据收发时的数据量会受到发送缓冲区和接收缓冲区大小的限制
数据收发时要注意字节序的问题(不同主机字节序的问题)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Apache POI入门学习

Apache POI入门学习 官网地址 excel中使用到的类读取excel表格内容表格内容maven依赖方式一测试结果 方式二测试结果 向excel中写入数据方式一方式二方式三测试结果 从 Excel 工作表中的公式单元格读取数据测试结果 Excel 工作表中写入公式单元格从受密码保护的Excel中读取数据…

Apple 发布新款 iPad Pro 和 iPad Air:性能和设计的巨大飞跃

Apple 发布新款 iPad Pro 和 iPad Air&#xff1a;性能和设计的巨大飞跃 概述 苹果公司最近的“Let Loose”活动在科技界掀起了轩然大波&#xff0c;推出了最新的 iPad Pro 和 iPad Air 型号&#xff0c;在性能、设计和功能方面取得了前所未有的改进。在本文中&#xff0c;我…

【XR806开发板试用】使用FDCM操作Flash记录开机次数

一、寻找系统分配的自定义用户数据地址 &#xff08;1&#xff09;XR806的Flash布局 如图1所示&#xff0c;FLASH的布局有两种&#xff1a; 1、没有开启OTA模式&#xff1b;Image1PaddingSysinfo 2、开启OTA模式&#xff1b;Image1PaddingSysinfoOTA area Image2 Padding 如图…

智算中心“火”了?引领算力发展新潮流

去年大模型的空前发展&#xff0c;人工智能也终于迎来了属于自己的“文艺复兴”&#xff0c;众多的模型相继发布&#xff0c;继而催生了整个行业对于智能算力需求的激增。 市场需求与技术驱动仿佛现实世界的左右脚&#xff0c;催动着世界文明的齿轮向前滚动。在全球经济角逐日…

django中的cookie与session

获取cookie request.COOKIE.GET 使用cookie response.set-cookie views.py from django.http import HttpResponse from django.shortcuts import render# Create your views here. def cookie_test(request):r HttpResponse("hello world")r.set_cookie(lan, py…

AQ6360 横河 光谱分析仪精华帖,收藏保存

AQ6360是一款由日本横河&#xff08;YOKOGAWA&#xff09;生产的光谱分析仪&#xff0c;其主要技术参数包括波长范围、波长精度和波长线性度等。AQ6360的波长范围为1200~1650nm &#xff0c;具有较高的波长精度&#xff0c;在1520~1580nm范围内为0.02nm&#xff0c;在1580~1620…

Colab/PyTorch - 001 PyTorch Basics

Colab/PyTorch - 001 PyTorch Basics 1. 源由2. PyTorch库概览3. 处理过程2.1 数据加载与处理2.2 构建神经网络2.3 模型推断2.4 兼容性 3. 张量介绍3.1 构建张量3.2 访问张量元素3.3 张量元素类型3.4 张量转换&#xff08;NumPy Array&#xff09;3.5 张量运算3.6 CPU v/s GPU …

从0开始学习python(六)

目录 前言 1、循环结构 1.1 遍历循环结构for 1.2 无限循环结构while 总结 前言 上一篇文章我们讲到了python的顺序结构和分支结构。这一章继续往下讲。 1、循环结构 在python中&#xff0c;循环结构分为两类&#xff0c;一类是遍历循环结构for&#xff0c;一类是无限循环结…

【工具推荐定制开发】一款轻量的批量web请求命令行工具支持全平台:hey,基本安装、配置、使用

背景 在开发 Web 应用的过程中&#xff0c;作为开发人员&#xff0c;为了确认接口的性能能够达到要求&#xff0c;我们往往需要一个接口压测工具&#xff0c;帮助我们快速地对我们所提供的 Web 服务发起批量请求。在接口联调的过程中&#xff0c;我们通常会用 Postman 等图形化…

气死!又被数据骗了!

做数据分析的人做的久了&#xff0c;就会自然而然产生一种想法&#xff0c;认为数据展示出来的东西一定是正确的。毕竟如果连我们自己都质疑数据分析的权威性和说服力&#xff0c;那我们数据分析人的工作不就成了白费功夫了嘛。 一开始&#xff0c;我也认为这是一条不可撼动的…

JVM认识之垃圾收集算法

一、标记-清除算法 1、定义 标记-清除算法是最基础的垃圾收集算法。它分为标记和清除两个阶段。先标记出所有需要回收的对象&#xff08;即垃圾&#xff09;&#xff0c;在标记完成后再统一回收所有垃圾对象。 2、优点和缺点 优点&#xff1a;实现简单缺点&#xff1a; 可能…

C++类和对象详解(一)

目录 面向过程和面向对象初步认识类的引入类的定义类的两种定义方式声明和定义全部放在类体中 声名定义分离 类的作用域成员变量命名规则建议访问限定符 类的封装类的实例化类对象模型类的对象大小的计算扩展 结构体内存对齐规则 感谢各位大佬对我的支持,如果我的文章对你有用,…

Linux系统一步一脚印式学习

Linux操作系统具有许多特点和优势。首先&#xff0c;它是开放源代码的&#xff0c;也就意味着任何人都可以对源代码进行查看和修改。其次&#xff0c;可以同时支持多个用户且可以同时执行多个任务&#xff0c;此外&#xff0c;Linux操作系统也非常稳定和安全。相对于其他操作系…

MyBatis认识

一、定义 MyBatis是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff08;Plain Old Java O…

关于zabbix简介及zabbix服务端的部署

文章目录 一、zabbix概念1、zabbix简介2、zabbix主要特点3、zabbix运行机制4、zabbix应用场景5、zabbix监控原理6、zabbix的子程序7、zabbix监控的架构模式7.1 server-client架构7.2 server-proxy-client架构7.3 master-node-client 二、部署zabbix1、服务器配置2、服务器环境3…

ruoyi-nbcio 基于flowable规则的多重并发网关的任意跳转

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; h…

认识下MapReduce

&#x1f50d; 什么是MapReduce&#xff1f; MapReduce是一种分布式计算模型&#xff0c;最初由Google提出&#xff0c;用于处理大规模数据集的并行计算。它将数据处理任务分解成独立的Map和Reduce两个阶段&#xff0c;以实现分布式计算和并行化处理。Map阶段负责将输入数据映…

自然语言处理(NLP)技术有哪些运用?

目录 一、自然语言处理&#xff08;NLP&#xff09;技术有哪些运用&#xff1f; 二、Python进行文本的情感分析 1、NLTK库: 2、TextBlob库: 三、错误排除 一、自然语言处理&#xff08;NLP&#xff09;技术有哪些运用&#xff1f; 自然语言处理&#xff08;NLP&#xff09…

DAY 3

1. #include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {this->resize(540,415);this->setFixedSize(540,415);//窗口标题this->setWindowTitle("盗版QQ");//窗口图标this->setWindowIcon(QIcon("E:\\qq\\pictrue\\pi…

520情人节送什么礼物?五款好物分享,情侣必看!

在浪漫的520情人节&#xff0c;为心爱的人挑选一份特别的礼物是每对情侣表达爱意的重要方式。市场上琳琅满目的选择让人眼花缭乱&#xff0c;究竟什么样的礼物能触动TA的心弦&#xff1f;本篇分享将为您精选五款既实用又充满情意的好物&#xff0c;无论是甜蜜的开始还是长久的陪…