xxsocket Class¶
封装底层bsd socket常用API,屏蔽各操作系统平台差异,yasio的起源。
特别注意
xxsocket除了 accept_n
以外的所有 xxx_n
接口均会将当前socket对象底层描述符设置为非阻塞模式,且不会恢复。
语法¶
成员¶
Name | Description |
---|---|
xxsocket::xxsocket | 构造一个 xxsocket 对象 |
公共方法¶
xxsocket::xxsocket¶
构造 xxsocket
对象。
xxsocket::xxsocket();
xxsocket::xxsocket(socket_native_type handle);
xxsocket::xxsocket(xxsocket&& right);
xxsocket::xxsocket(int af, int type, int protocol);
参数¶
handle
通过已有socket句柄构造 xxsocket
对象。
right
move构造函数右值引用。
af
ip协议地址类型。
protocol
协议类型,对于TCP/UDP直接传 0
就可以。
xxsocket::xpconnect¶
和远程服务器建立TCP连接。
参数¶
hostname
要连接服务器主机名,可以是 IP地址
或 域名
。
port
要连接服务器的端口。
local_port
本地通信端口号,默认值 0
表示随机分配。
注意¶
会自动检测本机支持的ip协议栈版本。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::xpconnect_n¶
和远程服务器建立TCP连接。
int xxsocket::xpconnect_n(const char* hostname, u_short port, const std::chrono::microseconds& wtimeout, u_short local_port = 0);
参数¶
hostname
要连接服务器主机名,可以是 IP地址
或 域名
。
port
要连接服务器的端口。
local_port
本地通信端口号,默认值 0
表示随机分配。
wtimeout
建立连接超时时间。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
会自动检测本机支持的ip协议栈。
xxsocket::pconnect¶
和远程服务器建立TCP连接。
int xxsocket::pconnect(const char* hostname, u_short port, u_short local_port = 0);
int xxsocket::pconnect(const endpoint& ep, u_short local_port = 0);
参数¶
hostname
要连接服务器主机名,可以是 IP地址
或 域名
。
ep
要连接服务器的地址。
port
要连接服务器的端口。
local_port
本地通信端口号,默认值 0
表示随机分配。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
不会检测本机支持的ip协议栈。
xxsocket::pconnect_n¶
和远程服务器建立TCP连接。
int pconnect_n(const char* hostname, u_short port, const std::chrono::microseconds& wtimeout, u_short local_port = 0);
int pconnect_n(const char* hostname, u_short port, u_short local_port = 0);
int pconnect_n(const endpoint& ep, const std::chrono::microseconds& wtimeout, u_short local_port = 0);
int pconnect_n(const endpoint& ep, u_short local_port = 0);
参数¶
hostname
要连接服务器主机名,可以是 IP地址
或 域名
。
ep
要连接服务器的地址。
port
要连接服务器的端口。
local_port
本地通信端口号,默认值 0
表示随机分配。
wtimeout
建立连接超时时间。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::pserve¶
开启本地TCP服务监听。
参数¶
addr
本机指定网卡 IP地址
。
ep
本机地址。
port
TCP监听端口。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
示例¶
// xxsocket-serve.cpp
#include <signal.h>
#include <vector>
#include "yasio/xxsocket.hpp"
using namespace yasio;
xxsocket g_server;
static bool g_stopped = false;
void process_exit(int sig)
{
if (sig == SIGINT)
{
g_stopped = true;
g_server.close();
}
printf("exit");
}
int main()
{
signal(SIGINT, process_exit);
if (g_server.pserve("0.0.0.0", 1219) != 0)
return -1;
const char reply_msg[] = "hi, I'm server\n";
do
{
xxsocket cs = g_server.accept();
if (cs.is_open())
{
cs.send(reply_msg, sizeof(reply_msg) - 1);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
} while (!g_stopped);
return 0;
}
xxsocket::swap¶
交换底层socket句柄。
参数¶
who
交换对象。
返回值¶
xxsocket
左值对象的引用。
xxsocket::open¶
打开一个socket。
参数¶
af
地址类型,例如 AF_INET
(ipv4),AF_INET6
(ipv6)。
type
socket类型, SOCK_STREAM
(TCP), SOCK_DGRAM
(UDP)。
protocol
协议,对于TCP/UDP,传 0
即可。
返回值¶
true
: 成功, false
失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::reopen¶
打开一个socket。
参数¶
af
地址类型,例如 AF_INET
(ipv4),AF_INET6
(ipv6)。
type
socket类型, SOCK_STREAM
(TCP), SOCK_DGRAM
(UDP)。
protocol
协议,对于TCP/UDP,传 0
即可。
返回值¶
true
: 成功, false
失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
如果socket已打开,此函数会先关闭,再重新打开。
xxsocket::is_open¶
判断socket是否已打开。
返回值¶
true
: 已打开, false
: 未打开。
xxsocket::native_handle¶
获取socket文件描述符。
返回值¶
socket文件描述符,yasio::inet::invalid_socket
表示无效socket。
xxsocket::release_handle¶
释放底层socket描述符控制权。
返回值¶
释放前的socket文件描述符
xxsocket::set_nonblocking¶
设置socket的非阻塞模式。
参数¶
nonblocking
true
: 非阻塞模式,false
: 阻塞模式。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::test_nonblocking¶
检测socket是否为非阻塞模式。
返回值¶
1
: 非阻塞模式, 0
: 阻塞模式。
注意¶
对于winsock2,未连接的 SOCK_STREAM
类型socket会返回 -1
。
xxsocket::bind¶
绑定socket本机地址。
参数¶
addr
本机指定网卡ip地址。
port
要绑定的端口。
ep
要绑定的本机地址。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::bind_any¶
绑定socket本机任意地址。
参数¶
ipv6
是否绑定本机任意IPv6地址
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::listen¶
开始监听来自TCP客户端的握手请求。
参数¶
backlog
最大监听数。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::accept¶
接受一个客户端连接。
返回值¶
和客户端通信的 xxsocket
对象。
xxsocket::accept_n¶
非阻塞方式接受一个客户端连接。
参数¶
new_sock
输出参数,和客户端通信的底层socket句柄引用
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
如果此函数返回0
,new_sock 会被设置为非阻塞模式。
调用此函数之前,请手动调用 xxsocket::set_nonblocking
将socket设置为非阻塞模式。
xxsocket::connect¶
建立连接。
参数¶
addr
远程主机ip地址。
port
远程主机端口。
ep
远程主机地址。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
TCP: 发起TCP三次握手
UDP: 建立4元组绑定
xxsocket::connect_n¶
建立连接。
int connect_n(const char* addr, u_short port, const std::chrono::microseconds& wtimeout);
int connect_n(const endpoint& ep, const std::chrono::microseconds& wtimeout);
int connect_n(const endpoint& ep);
参数¶
addr
远程主机ip地址。
port
远程主机端口。
ep
远程主机地址。
wtimeout
建立连接的超时时间。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
TCP: 发起TCP三次握手
UDP: 建立4元组绑定
xxsocket::disconnect¶
解除socket和远程主机的4元组绑定。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
仅支持UDP
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
只用于 SOCK_DGRAM
(UDP) 类型socket。
xxsocket::send¶
向远端发送指定长度数据。
参数¶
buf
要发送数据的起始字节地址。
len
要发送数据的长度。
flags
发送数据底层标记。
返回值¶
==len
: 成功, < len
失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::send_n¶
在超时时间内尽力向远端发送指定长度数据。
参数¶
buf
要发送数据的起始字节地址。
len
要发送数据的长度。
wtimeout
发送超时时间。
flags
发送数据底层标记。
返回值¶
==len
: 成功, < len
失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::recv¶
从内核去除远程主机发送过来的数据。
参数¶
buf
接收数据缓冲区。
len
接收数据缓冲区长度。
flags
接收数据底层标记。
返回值¶
==len
: 成功, < len
失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
此函数是否立即返回,取决于socket本身是否是 非阻塞模式
。
xxsocket::recv_n¶
在超时时间内尽力从内核取出指定长度数据。
参数¶
buf
接收数据缓冲区。
len
接收数据缓冲区长度。
wtimeout
接收超时时间。
flags
接收数据底层标记。
返回值¶
==len
: 成功, < len
失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::sendto¶
向远程主机发送 DGRAM
(UDP)数据。
参数¶
buf
待发送数据缓冲区。
len
待发送数据缓冲区长度。
to
发送目标地址。
flags
发送数据底层标记。
返回值¶
==len
: 成功, < len
失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::recvfrom¶
从内核去除远程主机发送过来的数据。
参数¶
buf
接收数据缓冲区。
len
接收数据缓冲区长度。
peer
接收数据来源,输出参数。
flags
接收数据底层标记。
返回值¶
==len
: 成功, < len
失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
此函数是否立即返回,取决于socket本身是否是 非阻塞模式
。
xxsocket::handle_write_ready¶
等待socket可写。
参数¶
wtimeout
等待超时时间。
返回值¶
0
: 超时, 1
: 成功, < 0
: 失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
通常当内核发送缓冲区没满的情况下,此函数会立即返回。
xxsocket::handle_read_ready¶
等待socket可读。
参数¶
wtimeout
等待超时时间。
返回值¶
0
: 超时, 1
: 成功, < 0
: 失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::local_endpoint¶
获取4元组通信的本地地址。
返回值¶
返回本地地址。
注意¶
如果没有调用过 xxsocket::connect
或者TCP连接3次握手未完成,那么返回的地址是 0.0.0.0
xxsocket::peer_endpoint¶
获取4元组通信的对端地址。
返回值¶
返回本地地址。
注意¶
如果没有调用过 xxsocket::connect
或者TCP连接3次握手未完成,那么返回的地址是 0.0.0.0
xxsocket::set_keepalive¶
设置TCP底层协议的心跳参数。
参数¶
flag
1
: 开启底层协议心跳,0
: 关闭。
idle
当应用层没有任何消息交互后,启动底层协议心跳探测的最大超时时间,单位(秒)。
interval
当没有收到心跳回应时,重复发送心跳探测报时间间隔,单位(秒)。
probes
当没有收到心跳回应时,最大探测次数,超过探测次数后,会触发应用层连接断开。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
示例¶
// xxsocket-keepalive.cpp
#include "yasio/xxsocket.hpp"
using namespace yasio;
using namespace inet;
int main(){
xxsocket client;
if(0 == client.pconnect("192.168.1.19", 80)) {
client.set_keepalive(1, 5, 10, 2);
}
return 0;
}
xxsocket::reuse_address¶
设置socket是否允许重用地址。
参数¶
reuse
是否重用。
注意¶
此函数一般用于服务器或者组播监听端口。
xxsocket::exclusive_address¶
是否明确不允许地址重用,以保护通信双方安全。
参数¶
exclusive
true
: 不允许,false
: 允许
注意¶
点击 查看 winsock
安全报告。
xxsocket::set_optval¶
设置socket选项。
参数¶
level
socket选项级别。
optname
选项类型。
optval
选项值。
返回值¶
0
: 成功, < 0
失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
此函数同bsd socket setsockopt
功能相同,只是使用模板封装,更方便使用。
xxsocket::get_optval¶
设置socket选项。
参数¶
level
socket选项级别。
optname
选项类型。
返回值¶
返回选项值。
注意¶
此函数同bsd socket getsockopt
功能相同,只是使用模板封装,更方便使用。
xxsocket::select¶
监听socket内核事件。
int select(fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const std::chrono::microseconds& wtimeout)
参数¶
readfds
可读事件描述符数组。
writefds
可写事件描述符数组。
exceptfds
异常事件描述符数组。
wtimeout
等待事件超时事件。
返回值¶
0
: 超时,> 0
: 成功, < 0
: 失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::shutdown¶
关闭TCP传输通道。
参数¶
how
关闭通道类型,可传以下枚举值
SD_SEND
: 发送通道SD_RECEIVE
: 接受通道SD_BOTH
: 全部关闭
返回值¶
0
: 成功, < 0
: 失败,通过 xxsocket::get_last_errno
获取错误码。
xxsocket::close¶
关闭socket,释放系统资源。
参数¶
shut_how
关闭通道类型,可以传以下枚举值
SD_SEND
: 发送通道SD_RECEIVE
: 接受通道SD_BOTH
: 全部关闭SD_NONE
: 全部关闭
返回值¶
0
: 成功, < 0
: 失败,通过 xxsocket::get_last_errno
获取错误码。
注意¶
如果 shut_how != SD_NONE
,此函数会先调用 shutdown
,再调用底层 close
。
xxsocket::tcp_rtt¶
获取TCP连接的RTT。
返回值¶
返回TCP的RTT时间,单位: 微秒
。
xxsocket::get_last_errno¶
获取最近一次socket操作错误码。
返回值¶
0
: 无错误, > 0
通过 xxsocket::strerror
转换为详细错误信息。
注意¶
此函数是线程安全的。
xxsocket::set_last_errno¶
设置socket操作错误码。
参数¶
error
错误码。
注意¶
此函数是线程安全的。
xxsocket::not_send_error¶
判断是否是发送时socket出现无法继续的错误。
参数¶
error
错误码。
返回值¶
true
: socket正常,false
: socket状态已经发生错误,应当关闭socket终止通讯。
注意¶
仅当发送操作返回值 < 0
时,调用此函数。
xxsocket::not_recv_error¶
判断是否是接收时socket出现无法继续的错误。
参数¶
error
错误码。
返回值¶
true
: socket正常,false
: socket状态已经发生错误,应当关闭socket终止通讯。
注意¶
仅当接收操作返回值 < 0
时,调用此函数。
xxsocket::strerror¶
将错误码转换为字符串。
参数¶
error
错误码。
返回值¶
错误信息的字符串。
xxsocket::strerror_r¶
将错误码转换为字符串,功能和xxsocket::strerror
一样,但此函数线程安全的。
参数¶
error
错误码。
buf
接受错误信息字符串的缓冲区
buflen
接受错误信息字符串的缓冲区大小
返回值¶
错误信息的字符串。
xxsocket::gai_strerror¶
将getaddrinfo
错误码转换为字符串。
参数¶
error
错误码。
返回值¶
错误信息的字符串。
xxsocket::resolve¶
解析域名包含的所有地址。
int resolve(std::vector<endpoint>& endpoints, const char* hostname, unsigned short port = 0, int socktype = SOCK_STREAM);
参数¶
endpoints
输出参数。
hostname
域名。
port
端口。
socktype
socket类型。
返回值¶
0
: 无错误, > 0
通过 xxsocket::strerror
转换为详细错误信息。
xxsocket::resolve_v4¶
解析域名包含的IPv4地址。
int resolve_v4(std::vector<endpoint>& endpoints, const char* hostname, unsigned short port = 0, int socktype = SOCK_STREAM);
参数¶
endpoints
输出参数。
hostname
域名。
port
端口。
socktype
socket类型。
返回值¶
0
: 无错误, > 0
通过 xxsocket::strerror
转换为详细错误信息。
xxsocket::resolve_v6¶
解析域名包含的IPv6地址。
int resolve_v6(std::vector<endpoint>& endpoints, const char* hostname, unsigned short port = 0, int socktype = SOCK_STREAM);
参数¶
endpoints
输出参数。
hostname
域名。
port
端口。
socktype
socket类型。
返回值¶
0
: 无错误, > 0
通过 xxsocket::strerror
转换为详细错误信息。
xxsocket::resolve_v4to6¶
仅解析域名包含的IPv4地址并转换为IPv6 V4MAPPED格式。
int resolve_v4to6(std::vector<endpoint>& endpoints, const char* hostname, unsigned short port = 0, int socktype = SOCK_STREAM);
参数¶
endpoints
输出参数。
hostname
域名。
port
端口。
socktype
socket类型。
返回值¶
0
: 无错误, > 0
通过 xxsocket::strerror
转换为详细错误信息。
xxsocket::resolve_tov6¶
解析域名包含的所有地址,IPv4地址会转换为IPv6 V4MAPPED格式。
int resolve_tov6(std::vector<endpoint>& endpoints, const char* hostname, unsigned short port = 0, int socktype = SOCK_STREAM);
参数¶
endpoints
输出参数。
hostname
域名。
port
端口。
socktype
socket类型。
返回值¶
0
: 无错误, > 0
通过 xxsocket::strerror
转换为详细错误信息。
xxsocket::getipsv¶
获取本机支持的IP协议栈标志位。
返回值¶
ipsv_ipv4
: 本机只支持IPv4协议。ipsv_ipv6
: 本机只支持IPv6协议。ipsv_dual_stack
: 本机支持IPv4和IPv6双栈协议。
注意¶
当返回值支持双栈协议是,用户应当始终优先使用IPv4通信,
例如智能手机设备
在同时开启wifi
和蜂窝网络
时,将会优先选择wifi,
而wifi通常是IPv4,详见: https://github.com/halx99/yasio/issues/130
示例¶
// xxsocket-ipsv.cpp
#include <vector>
#include "yasio/xxsocket.hpp"
using namespace yasio;
int main(){
const char* host = "github.com";
std::vector<ip::endpoint> eps;
int flags = xxsocket::get_ipsv();
if(flags & ipsv_ipv4) {
xxsocket::resolve_v4(eps, host, 80);
}
else if(flags & ipsv_ipv6) {
xxsocket::resolve_tov6(eps, host, 80);
}
else {
std::cerr << "Local network not available!\n";
}
return 0;
}
xxsocket::traverse_local_address¶
枚举本机地址。
参数¶
handler
枚举地址回调。
示例¶
// xxsocket-traverse.cpp
#include <vector>
#include "yasio/xxsocket.hpp"
using namespace yasio;
int main(){
int flags = 0;
xxsocket::traverse_local_address([&](const ip::endpoint& ep) -> bool {
switch (ep.af())
{
case AF_INET:
flags |= ipsv_ipv4;
break;
case AF_INET6:
flags |= ipsv_ipv6;
break;
}
return (flags == ipsv_dual_stack);
});
YASIO_LOG("Supported ip stack flags=%d", flags);
return flags;
}