mirror of
https://gitee.com/acl-dev/acl.git
synced 2024-12-15 09:20:52 +08:00
164 lines
3.9 KiB
C++
164 lines
3.9 KiB
C++
#pragma once
|
||
#include "../acl_cpp_define.hpp"
|
||
#include "../stdlib/string.hpp"
|
||
#include "../stdlib/noncopyable.hpp"
|
||
#if defined(_WIN32) || defined(_WIN64)
|
||
#include <WinSock2.h>
|
||
#endif
|
||
|
||
#if __cplusplus >= 201103L
|
||
#include <memory>
|
||
#endif
|
||
|
||
namespace acl {
|
||
|
||
class socket_stream;
|
||
|
||
enum {
|
||
OPEN_FLAG_NONE = 0,
|
||
OPEN_FLAG_NONBLOCK = 1, // 非阻塞模式
|
||
OPEN_FLAG_REUSEPORT = (1 << 1), // 端口复用,要求 Linux3.0 以上
|
||
OPEN_FLAG_FASTOPEN = (1 << 2), // 是否启用 Fast open(实验阶段)
|
||
OPEN_FLAG_EXCLUSIVE = (1 << 3), // 是否禁止复用地址
|
||
};
|
||
|
||
/**
|
||
* 服务端监听套接口类,接收客户端连接,并创建客户端流连接对象
|
||
*/
|
||
class ACL_CPP_API server_socket : public noncopyable {
|
||
public:
|
||
#if 0
|
||
/**
|
||
* 构造函数,调用本构造函数后需调用类方法 open 来监听指定服务地址
|
||
* @param backlog {int} 监听套接口队列长度
|
||
* @param block {bool} 是阻塞模式还是非阻塞模式
|
||
*/
|
||
server_socket(int backlog, bool block);
|
||
#endif
|
||
|
||
/**
|
||
* 构造函数
|
||
* @param flag {unsigned} 定义参见 OPEN_FLAG_XXX
|
||
* @param backlog {int} 监听套接口队列长度
|
||
*/
|
||
server_socket(unsigned flag, int backlog);
|
||
|
||
/**
|
||
* 构造函数,调用本构造函数后禁止再调用 open 方法
|
||
* @param sstream {ACL_VSTREAM*} 外部创建的监听流对象,本类仅使用
|
||
* 但并不释放,由应用自行关闭该监听对象
|
||
*/
|
||
server_socket(ACL_VSTREAM* sstream);
|
||
|
||
/**
|
||
* 构造函数,调用本构造函数后禁止再调用 open 方法
|
||
* @param fd {ACL_SOCKET} 外部创建的监听句柄,本类仅使用但并不释放,
|
||
* 由应用自行关闭该监听句柄
|
||
*/
|
||
#if defined(_WIN32) || defined(_WIN64)
|
||
server_socket(SOCKET fd);
|
||
#else
|
||
server_socket(int fd);
|
||
#endif
|
||
|
||
server_socket(void);
|
||
~server_socket(void);
|
||
|
||
/**
|
||
* 开始监听给定服务端地址
|
||
* @param addr {const char*} 服务器监听地址,格式为:
|
||
* ip:port;在 unix 环境下,还可以是域套接口,格式为:/path/xxx,在
|
||
* Linux 平台下,如果域套接口地址为:@xxx 格式,即第一个字母为 @ 则
|
||
* 内部自动启用 Linux 下的抽象域套接字方式(abstract unix socket)
|
||
* @return {bool} 监听是否成功
|
||
*/
|
||
bool open(const char* addr);
|
||
|
||
/**
|
||
* 判断当前监听套接口是否打开着
|
||
* @return {bool}
|
||
*/
|
||
bool opened(void) const;
|
||
|
||
/**
|
||
* 关闭已经打开的监听套接口
|
||
* @return {bool} 是否正常关闭
|
||
*/
|
||
bool close(void);
|
||
|
||
/**
|
||
* 将监听套接口从服务监听对象中解绑
|
||
* @return {SOCKET} 返回被解绑的句柄
|
||
*/
|
||
#if defined(_WIN32) || defined(_WIN64)
|
||
SOCKET unbind(void);
|
||
#else
|
||
int unbind(void);
|
||
#endif
|
||
|
||
/**
|
||
* 接收客户端连接并创建客户端连接流
|
||
* @param timeout {int} 当该值 >= 0 时,采用超时方式接收客户端连接,
|
||
* 若在指定时间内未获得客户端连接,则返回 NULL
|
||
* @param etimed {bool*} 当此指针非 NULL 时,如果因超时导致该函数返回
|
||
* NULL,则此值被置为 true
|
||
* @return {socket_stream*} 返回空表示接收失败或超时, 返回的流对象在用
|
||
* 完用户需要自行 delete 流对象.
|
||
*/
|
||
socket_stream* accept(int timeout = -1, bool* etimed = NULL);
|
||
|
||
#if __cplusplus >= 201103L
|
||
// 使用 c++11 shared_ptr 方式获得客户端流对象, 更安全地使用流对象
|
||
using shared_stream = std::shared_ptr<socket_stream>;
|
||
|
||
shared_stream shared_accept(int timeout = -1, bool* etimed = NULL) {
|
||
shared_stream ss(accept(timeout, etimed));
|
||
return ss;
|
||
}
|
||
#endif
|
||
|
||
/**
|
||
* 获得监听的地址
|
||
* @return {const char*} 返回值非空指针
|
||
*/
|
||
const char* get_addr(void) const {
|
||
return addr_.c_str();
|
||
}
|
||
|
||
/**
|
||
* 当正常监听服务器地址后调用本函数可以获得监听套接口
|
||
* @return {int}
|
||
*/
|
||
#if defined(_WIN32) || defined(_WIN64)
|
||
SOCKET sock_handle(void) const {
|
||
#else
|
||
int sock_handle(void) const {
|
||
#endif
|
||
return fd_;
|
||
}
|
||
|
||
/**
|
||
* 设置监听套接字的延迟接收功能,即当客户端连接上有数据时才将该连接返回
|
||
* 给应用,目前该功能仅支持 Linux
|
||
* @param timeout {int} 如果客户端连接在规定的时间内未发来数据,
|
||
* 也将该连接返回给应用
|
||
*/
|
||
void set_tcp_defer_accept(int timeout);
|
||
|
||
private:
|
||
int backlog_;
|
||
unsigned open_flag_;
|
||
bool unix_sock_;
|
||
string addr_;
|
||
|
||
#if defined(_WIN32) || defined(_WIN64)
|
||
SOCKET fd_;
|
||
SOCKET fd_local_;
|
||
#else
|
||
int fd_;
|
||
int fd_local_;
|
||
#endif
|
||
};
|
||
|
||
} // namespace acl
|