Socket¶
Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.
概述¶
IP地址与域名¶
IP地址是网络中的主机地址,用于两台网络主机能够互相找到彼此,这也是网络通信能够成功进行的基础。IP地址一般以点分十进制的字符串来表示,如 192.168.1.1。
我们日常访问的网站,其所在的服务器主机都有唯一的IP地址,网络中的主机不计其数,靠记IP地址的方式来区分不同的主机显然比较困难,并且同一个网站可能有多个不同的IP地址,或者IP地址会因为某种原因而更换。
因此,用域名表示网站地址的方式便应运而生,如我们常见的 www.baidu.com 比IP地址更容易被记住。因为实际的网络通信报文中使用的仍然是IP地址,所以需要使用 域名解析 协议去获取域名背后所对应的 IP地址。
下文的讲解均以 IPv4 协议为基础。
OSI七层模型¶
国际标准化组织(ISO)制定的一个用于计算机或通信系统的标准体系,一般被称为OSI(Open System Interconnection)七层模型。它为网络通信协议的实现提供了一个标准,通信双方在相同的层使用相同的协议,即可进行通信;就同一台设备而言,下层协议为上层协议提供了调用接口,将上层协议打包为底层协议,最终发送到网络上进行传输。
这七层分别为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
为了简化协议实现或者方便理解,五层模型或者四层模型的概念也诞生了。四层模型一般被提及的比较多,包括:应用层、传输层、网络层、网络接口层。
上文中的IP地址则属于网络层。
网络层用于把该主机所有的网络数据转发到网卡,经由物理层电路发送到网络中去。
为了方便阐述,下文将按照四层模型来进行讲解。
传输层协议¶
IP地址解决了网络中两台主机如何能够找到彼此,进而进行报文收发的问题。
试想下,一台主机上可能运行着多个应用程序,执行着不同的网络任务。这时,某台IP地址的主机收到了另一台主机的报文,这个报文数据要传递给哪个应用程序呢?
为了解决这个问题,人们基于网络层协议演化出了传输层协议,传输层协议为本地的网络应用分配不同的端口。收到网络层的报文后,根据不同的端口号,将数据递交给不同的应用。
为了应对不同的场景,传输层协议分为UDP和TCP协议。
TCP协议具有以下特点:
面向连接
每条连接只能有两个端点,即点对点
提供可靠的数据交付
全双工通信
面向字节流
根据不同的需求,基于TCP衍生出了一些应用层协议,不同的应用会默认指定一个端口号。端口号亦可根据实际情况更换。
常见的基于TCP的应用协议及端口如下:
序列号:建立连接的时候生成的随机数,通过SYN包传给主机,用来解决网络传输的乱序问题。
应答号:指下一次期望收到的数据序列号,配合上面的序列号一来解决丢包和乱序的问题。
控制位:(下面都是控制位的具体值,只能是0或者1)
ACK:表示此条消息为应答的消息,除了最初建立连接的SYN包之外的这个控制位都为1。
RST:表示TCP 连接中出现异常,需要强制断开连接
SYN:表示希望建立连接,在序列号字段进行初始值的设定。
FIN:表示后面不会再传输数据希望断开连接。
熟知端口号 |
协议 |
说明 |
|---|---|---|
0 |
– |
保留 |
7 |
echo |
报文回送服务器 |
20 |
FTP-DATA |
文件传输协议(数据) |
21 |
FTP |
文件传输协议 |
23 |
Telnet |
终端连接 |
25 |
SMTP |
简单邮件传输协议 |
53 |
DNS |
域名服务器 |
80 |
HTTP |
HTTP服务器 |
110 |
POP3 |
邮局协议版本3 |
1080 |
SOCKS |
代理服务器协议 |
确定TCP连接的五元组:协议类型(TCP)、本地IP、本地端口、远端IP、远端端口。UDP协议具有以下特点:
无连接
支持一对一、一对多和多对多通信
不保证可靠交付
全双工通信
面向报文
根据不同的需求,基于UDP衍生出了一些应用层协议,不同的应用会默认指定一个端口号。端口号亦可根据实际情况更换。
常见的基于UDP的应用协议及端口如下:
相比之下UDP因为是面向无连接,同时不提供复杂的控制机制,所以协议十分的简短,头部只有8个字节(64位),仅包括目标和源端口号,UDP首部和数据长度以及校验和(判断UDP是否完整)。
熟知端口号 |
协议 |
说明 |
|---|---|---|
0 |
– |
保留 |
7 |
echo |
报文回送服务器 |
53 |
nameserver |
域名服务器 |
67 |
bootps |
BOOT或DHCP服务器 |
68 |
bootpc |
BOOT或DHCP客户端 |
69 |
TFTP |
简单文件传输协议 |
123 |
NTP |
网络时间协议 |
161 |
SNMP |
简单网络管理协议 |
API说明¶
头文件¶
qcm_socket_adp.h
函数表¶
函数名 |
描述 |
|---|---|
qcm_socket_create() |
创建Socket套接字,支持TCP和UDP协议 |
qcm_socket_connect() |
TCP客户端连接远程服务器 |
qcm_socket_register_event() |
注册Socket事件 |
qcm_socket_read() |
从已连接的Socket接收TCP数据 |
qcm_socket_send() |
发送TCP数据到已连接的服务器 |
qcm_socket_listen() |
将Socket设置为监听模式(TCP服务器端) |
qcm_socket_accept() |
接受Socket连接请求(TCP服务器端) |
qcm_socket_close() |
关闭连接并释放Socket资源 |
qcm_socket_sendto() |
发送UDP数据到指定目的地址和端口 |
qcm_socket_recvfrom() |
接收UDP数据并获取发送方地址信息 |
qcm_socket_set_opt() |
设置Socket选项 |
qcm_socket_get_opt() |
获取Socket选项 |
qcm_socket_ssl_config() |
配置SSL参数(仅TCP) |
qcm_socket_ssl_connect() |
SSL连接认证(仅TCP) |
qcm_socket_ssl_is_init_already() |
检查SSL配置是否已初始化(仅TCP) |
qcm_socket_ssl_clean() |
释放SSL资源而不关闭Socket(仅TCP) |
qcm_socket_shutdown() |
关闭Socket的读写通道 |
qcm_socket_set_system_opt() |
设置系统选项 |
qcm_socket_get_system_opt() |
获取系统选项 |
qcm_socket_checkip_is_ip46() |
判断IP字符串类型(IPv4/IPv6/DNS) |
qcm_inet_ntop() |
网络IP地址转点分十进制字符串 |
qcm_socket_get_last_close_event() |
获取TCP最后关闭的原因 |
函数定义¶
qcm_socket_create¶
函数原型¶
int qcm_socket_create(qosa_uint8_t simid, qosa_uint8_t pdpcid, int family, int type, int protocol, int local_port, qosa_bool_t block);
功能描述¶
获取PDP ID指定的PDP上下文信息,创建socket,绑定本地IP地址和
local_port,返回用户句柄
参数描述¶
simid:SIM卡ID,用于指定使用哪个SIM卡的数据连接pdpcid:PDP上下文ID,用于指定PDP连接上下文family:地址族,如:QCM_AF_INET:IPv4地址族QCM_AF_INET6:IPv6地址族
type:Socket类型,如:QCM_SOCK_STREAM:TCP流式SocketQCM_SOCK_DGRAM:UDP数据报Socket
protocol:协议类型,如:QCM_TCP_PROTOCOL:TCP协议QCM_UDP_PROTOCOL:UDP协议
local_port:本地端口号,设为0表示由系统自动分配block:阻塞模式标识QOSA_TRUE:阻塞模式QOSA_FALSE:非阻塞模式
返回值¶
成功:返回对应的socket句柄
失败:返回负值,具体信息请参考
qcm_sock_err_code。
qcm_socket_connect¶
函数原型¶
int qcm_socket_connect(int s, qosa_ip_addr_t *remote_ip, int remote_port);
功能描述¶
TCP客户端连接远程服务器,应在DNS解析成功后执行
参数描述¶
s:要操作的Socket句柄(由qcm_socket_create创建)remote_ip:远程服务器IP地址结构体指针remote_port:要连接的远程端口号
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code。
qcm_socket_register_event¶
函数原型¶
int qcm_socket_register_event(int s, int event_mask, qcm_socket_event_cb func, void *argv);
功能描述¶
在非阻塞模式下监听对应的事件并设置回调,当产生了监听的事件则会执行回调函数,用户参数会传入回调函数中
参数描述¶
s:socket句柄event_mask:监听的事件,参考qcm_sock_event_mask_opt_efunc:事件产生时的回调函数argv:用户参数,传入事件回调函数中
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code。
qcm_socket_read¶
函数原型¶
int qcm_socket_read(int s, char *data, int sz);
功能描述¶
从已连接的Socket接收TCP数据
参数描述¶
s:已连接的Socket文件描述符data:接收数据缓冲区指针sz:接收缓冲区大小
返回值¶
成功:返回实际接收的字节数
注意:如果实际返回的长度小于
sz的大小,应再次调用发送函数来发送数据,以触发底层的“会阻塞”状态报告。失败:返回负值,具体信息请参考
qcm_sock_err_code。
qcm_socket_send¶
函数原型¶
int qcm_socket_send(int s, char *data, int sz);
功能描述¶
发送TCP数据到已连接的服务器
参数描述¶
s:已连接的Socket文件描述符data:待发送数据缓冲区指针sz:待发送数据长度
返回值¶
成功:返回实际发送的字节数
失败:返回负值,具体信息请参考
qcm_sock_err_code。
qcm_socket_listen¶
函数原型¶
int qcm_socket_listen(int s, int backlog);
功能描述¶
将Socket设置为监听模式,用于TCP服务器端等待客户端连接请求
参数描述¶
s:要操作的Socket句柄(由qcm_socket_create创建)backlog:等待连接队列的最大长度,用于处理同时到达的多个连接请求
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_accept¶
函数原型¶
int qcm_socket_accept(int s, qosa_ip_addr_t *remote_addr, int *remote_port, qosa_ip_addr_t *local_addr, int *local_port);
功能描述¶
接受Socket连接请求,新创建的Socket连接是否阻塞取决于监听Socket的阻塞参数配置
该函数需要在调用
qcm_socket_listen后执行
参数描述¶
s:要操作的Socket句柄(监听Socket)remote_addr:返回新连接的对端IP地址remote_port:返回新连接的对端端口号local_addr:返回本地IP地址local_port:返回本地端口号
返回值¶
成功:返回新连接的Socket句柄
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_close¶
函数原型¶
int qcm_socket_close(int s);
功能描述¶
关闭TCP连接并释放Socket资源
参数描述¶
s:待关闭的Socket文件描述符
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code。
qcm_socket_sendto¶
函数原型¶
int qcm_socket_sendto(int s, qosa_ip_addr_t *remote_addr, qosa_uint16_t remote_port, char *data, int sz);
功能描述¶
发送UDP数据到指定目的地址和端口
主要用于UDP Socket的数据发送
参数描述¶
s:已建立的Socket文件描述符(UDP类型)remote_addr:目的IP地址结构体指针remote_port:目的端口号data:待发送数据缓冲区指针sz:待发送数据长度
返回值¶
成功:返回实际发送的字节数
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_recvfrom¶
函数原型¶
int qcm_socket_recvfrom(int s, qosa_ip_addr_t *remote_addr, qosa_uint16_t *remote_port, char *data, int sz);
功能描述¶
从Socket接收数据,并将发送方的地址信息存储在指定位置
主要用于UDP Socket的数据接收
参数描述¶
s:已建立的Socket文件描述符(用于通信)remote_addr:接收到的数据的对方IP地址信息remote_port:接收到的数据的远程端口号data:接收数据的缓冲区指针sz:缓冲区大小(字节数)
返回值¶
成功:返回实际接收的字节数
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_set_opt¶
函数原型¶
int qcm_socket_set_opt(int s, qcm_socke_option_e opt, void *value);
功能描述¶
设置Socket选项
参数描述¶
s:已建立的Socket文件描述符(用于通信)opt:选项名称,用于指定要设置的选项value:存储选项值的缓冲区指针
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_get_opt¶
函数原型¶
int qcm_socket_get_opt(int s, qcm_socke_option_e opt, void *value);
功能描述¶
获取Socket选项接口
参数描述¶
s:已建立的Socket文件描述符(用于通信)opt:选项名称,用于指定要获取的选项value:存储选项值的缓冲区指针
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_ssl_config¶
函数原型¶
qcm_sock_err_code qcm_socket_ssl_config(int s, qcm_ssl_config_t *ssl_ptr, const char *hostname, qosa_bool_t block);
功能描述¶
配置要使用的SSL配置信息
注意:此功能仅在定义了
CONFIG_QCM_VTLS_FUNC时可用
参数描述¶
s:已建立的Socket文件描述符(用于通信)ssl_ptr:SSL配置文件的指针hostname:主机名block:配置SSL握手会话是阻塞还是非阻塞模式
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_ssl_connect¶
函数原型¶
qcm_sock_err_code qcm_socket_ssl_connect(int s);
功能描述¶
连接SSL服务器
函数阻塞和非阻塞模式由
qcm_socket_ssl_config中配置的block参数控制注意:此功能仅在定义了
CONFIG_QCM_VTLS_FUNC时可用
参数描述¶
s:已建立的Socket文件描述符(用于通信)
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_ssl_is_init_already¶
函数原型¶
qosa_bool_t qcm_socket_ssl_is_init_already(int s);
功能描述¶
获取SSL配置是否已经初始化
注意:此功能仅在定义了
CONFIG_QCM_VTLS_FUNC时可用
参数描述¶
s:已建立的Socket文件描述符(用于通信)
返回值¶
QOSA_TRUE:SSL配置已初始化QOSA_FALSE:SSL配置未初始化
qcm_socket_ssl_clean¶
函数原型¶
qcm_sock_err_code qcm_socket_ssl_clean(int s);
功能描述¶
仅释放SSL资源而不关闭Socket句柄
注意:此功能仅在定义了
CONFIG_QCM_VTLS_FUNC时可用
参数描述¶
s:已建立的Socket文件描述符(用于通信)
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_shutdown¶
函数原型¶
int qcm_socket_shutdown(int s, int how);
功能描述¶
Socket关闭函数,用于关闭读取(RD)、写入(WR)通道
原始
socket shutdown函数执行成功返回0,失败返回-1并设置全局errno值错误码说明:
EBADF:socket不是有效的socket描述符,通常发生在socket未打开或已关闭时EINVAL:how参数未设置为有效值ENOBUFS:没有足够的系统资源来完成此调用,通常发生在系统资源紧张时ENOTCONN:socket未连接,如果尝试关闭未连接的socket,将返回此错误ENOTSOCK:描述符指向文件而不是socket
参数描述¶
s:要操作的Socket句柄how:对应的操作方向QCM_SHUT_RD:关闭读取通道QCM_SHUT_WR:关闭写入通道QCM_SHUT_RDWR:同时关闭读取和写入通道
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_set_system_opt¶
函数原型¶
int qcm_socket_set_system_opt(qcm_socket_system_option_e opt, void *value);
功能描述¶
设置系统选项
参数描述¶
opt:系统选项枚举value:选项值指针
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_get_system_opt¶
函数原型¶
int qcm_socket_get_system_opt(qcm_socket_system_option_e opt, void *value);
功能描述¶
获取系统选项
参数描述¶
opt:系统选项枚举value:存储选项值的缓冲区指针
返回值¶
成功:返回0
失败:返回负值,具体信息请参考
qcm_sock_err_code
qcm_socket_checkip_is_ip46¶
函数原型¶
int qcm_socket_checkip_is_ip46(char *ip_string);
功能描述¶
简单判断输入字符串是IPv4、IPv6还是DNS类型
参数描述¶
ip_string:要检查的IP字符串
返回值¶
QCM_AF_INET:表示IPv4地址QCM_AF_INET6:表示IPv6地址0:表示未知类型
-1:表示执行失败
qcm_inet_ntop¶
函数原型¶
const char *qcm_inet_ntop(int af, const void *src, char *dst, int size);
功能描述¶
网络IP地址到点分十进制字符串的转换
参数描述¶
af:地址族(AF_INET或AF_INET6)src:网络字节序的IP地址dst:点分十进制字符串IP地址缓冲区size:点分十进制字符串IP地址缓冲区大小
返回值¶
成功:返回指向dst的指针
失败:返回NULL
备注
注意:
输入参数是网络字节序,输出参数是点分十进制字符串,如"192.168.1.100"
此函数解决与之前平台格式大小不一致的问题,字符转换为大写显示
qcm_socket_get_last_close_event¶
函数原型¶
int qcm_socket_get_last_close_event(int s);
功能描述¶
获取TCP最后关闭的原因
参数描述¶
s:要操作的Socket句柄
返回值¶
返回具体的关闭原因代码
结构体定义¶
typedef struct
{
int on_off; /*!< option on/off */
int linger_val; /*!< linger time in seconds */
} qcm_socket_linger_t;
枚举定义¶
typedef enum
{
QCM_SOC_STATE_NONE = 0,
QCM_SOC_STATE_CONNECTING, /*!< Socket is in connecting state */
QCM_SOC_STATE_CONNECT, /*!< Socket connection successful */
QCM_SOC_STATE_LISTEN, /*!< Socket is in listening state */
QCM_SOC_STATE_CLOSING, /*!< Socket encountered error and is preparing to close */
QCM_SOC_STATE_CLOSED = QCM_SOC_STATE_NONE, /*!< Socket connection closed */
} qcm_socket_state;
typedef enum
{
QCM_SOCK_LINGER_OPT = 1, /*!< Used to set delayed close time */
QCM_SOCK_UNREAD_OPT = 2, /*!< Used to get unread status in buffer */
QCM_TCP_ACK_OPT = 3, /*!< Used to get the number of ACKs in current socket connection */
QCM_SOCK_REUSEADDR_OPT = 4, /*!< Used to configure whether to enable port address reuse option */
QCM_IP_TTL_OPT = 5, /*!< Used to set TTL field, indicating the maximum number of hops allowed for IP packet forwarding in the network */
#ifdef CONFIG_QOSA_LINUX_PLATFROM_CFG
QCM_TCP_UNACK_OPT = 6, /*!< Used to get the number of unacknowledged ACKs in current socket connection */
#endif
} qcm_socke_option_e;
typedef enum
{
QCM_TCP_KEEPALIVE_OPT = 1, /*!< Used to configure whether to enable TCP keepalive option function */
QCM_TCP_KEEPIDLE_OPT = 2, /*!< Used to configure keepalive IDLE idle time */
QCM_TCP_KEEPINTVL_OPT = 3, /*!< Used to configure keepalive probe packet interval time */
QCM_TCP_KEEPCNT_OPT = 4, /*!< Used to configure the number of keepalive probe packets sent */
QCM_TCP_WINDOWS_SCALING_OPT = 5, /*!< Used to modify TCP Windows scale factor of system protocol stack */
QCM_TCP_RETRY_TIME_OPT = 6, /*!< Configure TCP retransmission interval time, must be configured together with QCM_TCP_MAX_BACKOFFS */
QCM_TCP_RETRY_COUNT_OPT = 7, /*!< Configure TCP retransmission count, must be configured together with QCM_TCP_RETRY_TIME_OPT */
QCM_TCP_DELAY_ACK_OPT
= 8, /*!< TCP protocol layer delayed sending, preventing TCP internal delay waiting for data packet sending, but still cannot completely avoid */
QCM_TCP_TIMEWAIT_FAST_RELEASE_OPT = 9, /*!< Control underlying TCP close time wait state fast release action */
QCM_TCP_RECV_WINDOWS_OPT = 10, /*!< TCP protocol layer receive window size */
QCM_TCP_SEND_WINDOWS_OPT = 11, /*!< TCP protocol layer send window size */
QCM_UDP_FILTER_OPT = 12, /*!< Configure whether to filter UDP packets, preventing unrecorded UDP packet access */
QCM_TCP_MSS_OPT = 13, /*!< TCP MSS configuration */
QCM_DNS_CACHE_OPT = 14, /*!< DNS cache configuration */
QCM_DNS_RETRY_TIME_OPT = 15, /*!< DNS retry time configuration */
QCM_DNS_RETRY_COUNT_OPT = 16, /*!< DNS retry count configuration */
} qcm_socket_system_option_e;
typedef enum
{
QCM_SOCK_CONNECT_EVENT = 0x01, /*!< TCP connection event notification */
QCM_SOCK_READ_EVENT = 0x02, /*!< Socket read event notification */
QCM_SOCK_WRITE_EVENT = 0x04, /*!< Socket write event notification */
QCM_SOCK_ACCEPT_EVENT = 0x08, /*!< Socket accept event notification */
QCM_SOCK_CLOSE_EVENT = 0x10, /*!< Socket close event notification */
QCM_SOCK_SSL_HD_TIMEOUT_EVENT = 0x20, /*!< SSL handshake failure */
QCM_SOCK_SENDENDACK_EVENT = 0x40, /*!< TCP ACK response event notification */
QCM_SOCK_NET_DOWN_EVENT = 0x80, /*!< Network initiated disconnection event notification */
QCM_SOCK_MAX
} qcm_sock_event_mask_opt_e;
typedef enum
{
QCM_SOCK_SUCCESS = 0, /*!< Socket operation successful */
QCM_SOCK_OUT_MEM = -1, /*!< Memory allocation error */
QCM_SOCK_WODBLOCK = -2, /*!< Wouldblock error */
QCM_SOCK_INVALID_PARAM = -3, /*!< Invalid parameter */
QCM_SOCK_DNS_FAIL = -4, /*!< DNS resolution error */
QCM_SOCK_NOT_ALLOW = -5, /*!< Operation not allowed */
QCM_SOCK_BROKEN = -6, /*!< */
QCM_SOCK_INTERNAL_ERROR = -7, /*!< Internal error */
QCM_SOCK_TIMEROUT = -8, /*!< Timeout error */
QCM_SOCK_PDP_NO_ACTIVE = -9, /*!< PDP not activated */
#ifdef CONFIG_QCM_VTLS_FUNC
QCM_SOCK_SSL_INIT_ERROR = -9, /*!< SSL initialization error */
QCM_SOCK_SSL_CONN_ERROR = -10, /*!< SSL connection error */
#endif
} qcm_sock_err_code;