ESP32-socket编程

ESP32-socket编程

一.socket介绍

Socket(套接字):这是计算机网络中的一个重要概念,指的是一个端点,用于在网络中的两个程序之间建立通信。Socket可以理解为一种通信机制,它使得不同的程序能够在TCP/IP网络上相互传输数据。基本上,Socket为网络通信提供了接口,允许程序通过网络发送和接收数据。

Socket API:这是操作系统提供的一组应用程序接口,允许开发者使用Socket进行网络编程。它通常包括创建Socket、绑定Socket到一个地址、监听连接、接受连接和发送/接收数据等功能。常见的编程语言如Python、C、Java等都有相关的Socket库,可以方便地进行网络通信。

Socket 类型:

Stream Sockets(流套接字):通常用于TCP协议,提供有序、可靠的双向流数据传输。
Datagram Sockets(数据报套接字):通常用于UDP协议,适合需要较少流量的应用,传输速度快但不保证可靠性。

在通信过程中,socket一定是成对出现的。

二.socket结构体介绍

在这里插入图片描述

2.1 struct sockaddr_in

struct sockaddr_in {
  u8_t            sin_len;
  sa_family_t     sin_family;
  in_port_t       sin_port;
  struct in_addr  sin_addr;
#define SIN_ZERO_LEN 8
  char            sin_zero[SIN_ZERO_LEN];
};
  • 介绍
    通常在创建和使用socket时用作服务器和客户端的地址结构体。服务器可以使用该结构体来绑定到特定的端口和IP地址,通过 bind() 函数使用它;而客户端则可以使用它来指定要连接的服务器的地址,通过 connect() 函数使用。

  • 成员

    • u8_t sin_len:这个字段表示结构体的大小,通常在现代程序中可能不再使用,但在某些平台上,它对确保 API 的兼容性是有用的。
    • sa_family_t sin_family:这个字段指定地址的类型。在使用 IPv4 时,它的值通常设置为 AF_INET。这个字段帮助操作系统识别使用的是哪种协议。
    • in_port_t sin_port:该字段存储端口号,用于标识特定的服务或应用程序。注意,端口号需要转换为网络字节序(大端字节序),通常使用 htons() 函数进行转换。
    • struct in_addr sin_addr:这个字段持有目标 IP 地址,使用结构体 in_addr 来表示。通常,使用 inet_pton() 或 ** inet_addr() ** 等函数来将字符串形式的IP地址转换为该结构体。
    • char sin_zero[SIN_ZERO_LEN]:保留用,通常填充为零

三.socket——API函数介绍

3.1 IP地址转换函数与宏函数

3.1.1 int inet_pton(int af, const char *src, void *dst);

  • 参数

    • int af:
    • sa_family_t sin_family:地址族,指定要转换的地址类型。常见的值包括:
      AF_INET:用于 IPv4 地址
      AF_INET6:用于 IPv6 地址
    • const char *src:指向一个字符串的指针,表示要转换的源地址。这个地址通常为点分十进制格式的 IPv4 地址(例如 “192.168.1.1”),或是括号格式的 IPv6 地址(例如 “[2001:db8::1]”)。
    • void *dst:指向目标内存的指针,用于存储转换后的二进制地址。对于 IPv4,通常会将其存储为 struct in_addr 类型;对于 IPv6,通常会将其存储为 struct in6_addr 类型。
  • 参数

    • 返回值
    • 返回值为 1 表示成功。
    • 返回值为 0 表示提供的地址字符串不是有效地址格式。
      返回值为 -1 表示出错(例如不支持的地址族),可以通过 errno 获取错误信息。

3.1.2 宏函数 inet_addr(const char *strptr)

是一个用于将 IPv4 地址的文本表示转换为网络字节序的二进制格式的函数

  • 参数

    • const char *strptr:指向一个以点分十进制形式表示的 IP 地址的字符串,例如 “192.168.1.1”。
  • 返回值

    • 如果转换成功,返回转换后的网络字节序的二进制形式的 IP 地址。
    • 如果输入字符串不是有效的 IP 地址,返回 INADDR_NONE(通常为 0xFFFFFFFF),这表明地址无效。

3.2 socket通信API函数

3.2.1 socket函数

int socket(int domain,int type,int protocol)
  • 参数

    • int domain:指定套接字的地址域,也就是协议族。这决定了数据将如何在网络中传输。
      常见的值:
      AF_INET:表示 IPv4 协议。
      AF_INET6:表示 IPv6 协议。
      AF_UNIX:表示本地(Unix)套接字,用于在同一台主机上的进程间通信。
    • int type: 地址族,指定要转换的地址类型。常见的值包括:
      AF_INET:用于 IPv4 地址
      AF_INET6:用于 IPv6 地址
    • int protocol:指定套接字的类型,定义了套接字的特性和通信方式。
      常见的值:
      SOCK_STREAM:面向连接的流套接字,提供可靠的双向字节流(通常用于 TCP)。
      SOCK_DGRAM:无连接的数据报套接字,提供不可靠的消息传输(通常用于 UDP)。
      SOCK_RAW:原始套接字,允许直接对网络层协议进行操作(通常不常用,需要超级用户权限)。
  • 返回值

    • 返回一个整型的套接字描述符(socket descriptor),表示已创建的套接字。
    • 如果创建失败,返回 -1,并设置 errno 以指示错误原因(例如,内存不足、地址族不支持等)。

3.2.2 conne函数

int connect(int s,const struct sockaddr *name,socklen_t namelen)

主要用于客户端

  • 参数

  • int s:这是一个套接字描述符,通常通过 socket 函数创建。它标识正在尝试连接的套接字。

  • const struct sockaddr *name 指向 sockaddr 结构的指针,包含目标服务器的地址信息。这可以是 sockaddr_in(用于 IPv4 地址)或 sockaddr_in6(用于 IPv6 地址)结构。该结构定义了要连接的地址(IP 地址和端口号)。

  • socklen_t namelen:这个参数指定 name 指向的地址结构的长度。对于 sockaddr_in,可以使用 sizeof(struct sockaddr_in);对于 sockaddr_in6,使用 sizeof(struct sockaddr_in6)。

  • 返回值

    • 成功时返回 0。
    • 失败时返回 -1,并设置 errno 值描述错误原因,例如连接失败、超时、目标不可达等。

3.2.3 bind函数

int bind(int s,const struct sockaddr *name, socklen_t namelen)

介绍:
bind 函数是在网络编程中用于将一个套接字(socket)与一个特定的地址(IP 地址和端口号)进行关联的函数。此函数通常在服务器端使用,以便让操作系统知道监听和接收的数据包应发送到哪个地址。
注意:bind 和 connect 是在网络编程中用于处理套接字的两个不同函数。它们的主要区别在于使用场景、目的和适用的角色(客户端与服务器)。以下是详细的比较:主要在服务器端使用,目的是使服务器能够监听来自客户端的连接请求或接收数据包。

  • 参数

    • int s:这是一个套接字描述符,通常通过 socket 函数创建。它标识正在尝试连接的套接字。
    • const struct sockaddr *name 指向 sockaddr 结构的指针,包含目标服务器的地址信息。这可以是 sockaddr_in(用于 IPv4 地址)或 sockaddr_in6(用于 IPv6 地址)结构。该结构定义了要连接的地址(IP 地址和端口号)。
    • socklen_t namelen:这个参数指定 name 指向的地址结构的长度。对于 sockaddr_in,可以使用 sizeof(struct sockaddr_in);对于 sockaddr_in6,使用 sizeof(struct sockaddr_in6)。
  • 返回值

    • 成功时返回 0。
    • 失败时返回 -1,并设置 errno 值描述错误原因,例如连接失败、超时、目标不可达等。

3.2.4 listen函数

int listen(int s, int backlog);

listen 函数的主要作用是在服务器端设置一个套接字,以便它可以接受来自客户端的连接请求。具体来说,它在以下几个方面起着重要作用:listen 主要用于 TCP 套接字,因为 TCP 是面向连接的协议,需要建立连接才能进行数据传输。对于 UDP 套接字,通常不需要调用 listen,因为 UDP 是无连接的。

  • 参数

  • int s:这是一个套接字描述符,通常通过 socket 和 bind 函数创建并绑定。此套接字用于等待来自客户端的连接请求。

  • int backlog 此参数指定在开始接受连接之前,系统可以排队的最大连接请求数。换句话说,如果有多个客户端同时尝试连接,而服务器尚未处理这些连接,则可以将这些连接请求保留在队列中,直到服务器准备好处理它们。
    它的值通常设置为大于0的整数,意味着可以保持 backlog 个连接请求在排队状态(系统会根据具体实现限制这个值的大小)。注意,某些系统可能会对 backlog 的值设置上限。

  • 返回值

    • 成功时返回 0。
    • 失败时返回 -1,并设置 errno 值来指示错误的原因,常见的错误包括:
      套接字未处于连接状态(如未调用 bind)。
      非法或过大的 backlog 值。。

3.2.5 send函数

ssize_t send(int s, const void *dataptr, size_t size, int flags);
  • 参数

  • int s:这是一个套接字描述符,通常通过 socket() 函数创建,并且已经通过 connect() 与远端主机建立了连接。这个套接字用于指定要通过哪个连接发送数据。

  • const void *dataptr 这是一个指向要发送数据的缓冲区的指针。这个数据可以是任何类型,通常是一个字符数组或字符串。发送的数据将根据 size 参数的指定长度进行处理。

  • size_t size:这是要发送的数据字节数,指定 dataptr 指向的数据的长度。调用者需要确保这个大小不会超过缓冲区的实际大小,以防止缓冲区溢出。

  • int flags:0:默认标志,表示使用常规发送操作

  • 返回值

    • 成功时,返回实际发送的字节数。
    • 如果发送失败,返回 -1,并设置 errno 值来指示错误原因,例如:
      套接字未连接(ENOTCONN)
      网络不可达(ENETUNREACH)
      连接被对方关闭(ECONNRESET)等

3.2.6 accept函数

int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

accept 函数主要用于 TCP 协议中。当服务器使用 TCP 套接字与客户端进行通信时,accept 是建立连接的关键步骤。accept会阻塞等待客户端的连接

  • 参数

  • int s:这是一个套接字描述符,它是由 socket() 创建并通过 bind() 和 listen() 设置为监听状态的。s 表示服务器用于监听客户端请求的套接字。

  • struct sockaddr *addr 这是一个指向 sockaddr 结构体的指针,用于存储客户端的地址信息。当客户端成功连接后,accept 函数会填充这个结构体,提供客户端的地址和端口信息。
    这个参数可以为 NULL,如果你不需要获取客户端的地址信息的话。

  • socklen_t *addrlen:这是一个指向 socklen_t 类型变量的指针,表示 addr 结构体的大小。在调用 accept 之前,需要将这个值设置为 addr 指向的结构体的大小(例如,sizeof(struct sockaddr_in))。
    在调用 accept 之后,这个值将被更新为实际填充的地址结构的大小。

  • 返回值

    • 成功时,返回一个新的套接字描述符,用于与连接的客户端进行通信。这个新套接字是独立的,允许你同时处理多个连接。
    • 失败时返回 -1,并设置 errno 以指示错误原因。常见的错误包括:
      套接字未处于监听状态(ENOTCONN)
      由于无效的参数或资源限制等导致的连接错误(例如,ENOMEM)。

3.2.7 recv函数

ssize_t recv(int s,void *mem,size_t len,int flags)

阻塞等待客户端或者服务端,直到等待接收到消息

  • 参数

  • int s:这是一个套接字描述符,通常通过 socket() 函数创建,并且已经通过 connect() 与远端主机建立了连接。这个套接字用于指定要通过哪个连接发送数据。

  • void *mem 这是一个指向内存缓冲区的指针,用于存储接收到的数据。这个缓冲区应该预先分配足够的内存以容纳要接收的数据。

  • size_t size:这个参数指定希望接收的字节数。它告知 recv 函数最多应该接收多少数据。如果可用数据超过这个大小,recv 可能只会返回部分数据。

  • int flags:0:默认标志,表示使用常规发送操作

  • 返回值

    • 成功时,返回接收到的字节数。如果连接被对方关闭(EOF),返回 0。。
    • 如果出错,返回 -1,并设置 errno 变量以指示错误原因,例如:
      套接字无效(EBADF)
      网络中断(EPIPE)
      超时(ETIMEDOUT)等。

四.TCP通信协议

SYN:同步序列骗号(Synchronize Sequence Numbers)** 表示连接请求 **
ACK:(Acknowledge character)即是确认字符,在数据通信中,接收站发给发送站的一种传
输类控制字符。表示发来的** 数据已确认接收无误 **。
在这里插入图片描述
在这里插入图片描述

4.1TCP通信流程

  • server:
    1.socket() 创建socket
    2.bind() 绑定服务器地址结构
    3.listen() 设置监听上限
    4.accpet() 阻塞监听客户端连接
    5.read() 读socket获取客户端数据
    6.write(fd)
    7.close()

  • client:
    1.socket() 创建socket
    2.connect() 与服务器建立连接
    3.write() 写数据到socket
    4.read() 读转换后的数据显示读取结果
    5.close()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值