从零开始实现一个C++高性能服务器框架----Socket模块
此项目是根据sylar框架实现,是从零开始重写sylar,也是对sylar丰富与完善
项目地址:https://gitee.com/lzhiqiang1999/server-framework
简介
项目介绍:实现了一个基于协程的服务器框架,支持多线程、多协程协同调度;支持以异步处理的方式提高服务器性能;封装了网络相关的模块,包括socket、http、servlet等,支持快速搭建HTTP服务器或WebSokcet服务器。
详细内容:日志模块,使用宏实现流式输出,支持同步日志与异步日志、自定义日志格式、日志级别、多日志分离等功能。线程模块,封装pthread相关方法,封装常用的锁包括(信号量,读写锁,自旋锁等)。IO协程调度模块,基于ucontext_t实现非对称协程模型,以线程池的方式实现多线程,多协程协同调度,同时依赖epoll实现了事件监听机制。定时器模块,使用最小堆管理定时器,配合IO协程调度模块可以完成基于协程的定时任务调度。hook模块,将同步的系统调用封装成异步操作(accept, recv, send等),配合IO协程调度能够极大的提升服务器性能。Http模块,封装了sokcet常用方法,支持http协议解析,客户端实现连接池发送请求,服务器端实现servlet模式处理客户端请求,支持单Reator多线程,多Reator多线程模式的服务器。
Socket模块
1. 主要功能
- 对Linux下socket相关方法的封装,包括bind、listen、connect、read/write系列等方法。
- 支持快速创建TCP、UDP对应的Socket。
2. 功能演示
- 模拟一个请求百度的客户端,并打印出响应
IPAddress::ptr addr = Address::LookupAnyIPAddress("www.baidu.com:80");
// 创建socket
Socket::ptr socket = Socket::CreateTCP(addr);
// 连接
socket->connect(addr);
//发送数据
const char buf[] = "GET / HTTP/1.1\r\n\r\n";
int rt = socket->send(buf, sizeof(buf));
if(rt <= 0) {
LOG_INFO(g_logger) << "send fail";
return;
}
//接收数据
std::string buffers;
buffers.resize(4096);
rt = socket->recv(&buffers[0], 4096);
if(rt <= 0) {
LOG_INFO(g_logger) << "recv fail";
return;
}
LOG_INFO(g_logger) << buffers;
3. 模块介绍
3.1 Socket
- 对socket相关方法的封装,包括以下内容
- 创建各种类型的套接字对象的方法(TCP套接字,UDP套接字,Unix域套接字)
- 设置套接字选项,比如超时参数
- bind/connect/listen方法,实现绑定地址、发起连接、发起监听功能
- accept方法,返回连入的套接字对象
- 发送、接收数据的方法
- 获取本地地址、远端地址的方法
- 获取套接字类型、地址类型、协议类型的方法
- 取消套接字读、写的方法
class Socket : public std::enable_shared_from_this<Socket>, Noncopyable
{
public:
typedef std::shared_ptr<Socket> ptr;
typedef std::weak_ptr<Socket> weak_ptr;
// 创建TCP Socket(满足地址类型)
static Socket::ptr CreateTCP(johnsonli::Address::ptr address);
// 创建UDP Socket(满足地址类型)
static Socket::ptr CreateUDP(johnsonli::Address::ptr address);
// 创建IPv4的TCP Socket
static Socket::ptr CreateTCPSocket();
// 创建IPv4的UDP Socket
static Socket::ptr CreateUDPSocket();
// 创建IPv6的TCP Socket
static Socket::ptr CreateTCPSocket6();
// 创建IPv6的UDP Socket
static Socket::ptr CreateUDPSocket6();
Socket(int family, int type, int protocol = 0);
virtual ~Socket();
int64_t getSendTimeout(); // 获取发送超时时间(毫秒)
void setSendTimeout(int64_t v); // 设置发送超时时间(毫秒)
int64_t getRecvTimeout(); // 获取接受超时时间(毫秒)
void setRecvTimeout(int64_t v); // 设置接受超时时间(毫秒)
// 获取sockopt @see getsockopt
bool getOption(int level, int option, void* result, socklen_t* len);
// 获取sockopt模板 @see getsockopt
template<class T>
bool getOption(int level, int option, T& result)
{
socklen_t length = sizeof(T);
return getOption(level, option, &result, &length);
}
// 设置sockopt @see setsockopt
bool setOption(int level, int option, const void* result, socklen_t len);
// 设置sockopt模板 @see setsockopt
template<class T>
bool setOption(int level, int option, const T& value)
{
return setOption(level, option, &value, sizeof(T));
}
/**
* @brief 接收connect链接
* @return 成功返回新连接的socket,失败返回nullptr
* @pre Socket必须 bind , listen 成功
*/
virtual Socket::ptr accept();
/**
* @brief 绑定地址
* @param[in] addr 地址
* @return 是否绑定成功
*/
virtual bool bind(const Address::ptr addr);
/**
* @brief 连接地址
* @param[in] addr 目标地址
* @param[in] timeout_ms 超时时间(毫秒)
*/
virtual bool connect(const Address::ptr addr, uint64_t timeout_ms = -1);
virtual bool reconnect(uint64_t timeout_ms = -1);
/**
* @brief 监听socket
* @param[in] backlog 未完成连接队列的最大长度
* @result 返回监听是否成功
* @pre 必须先 bind 成功
*/
virtual bool listen(int backlog = SOMAXCONN);
/**
* @brief 关闭socket
*/
virtual bool close();
/**
* @brief 发送数据
* @param[in] buffer 待发送数据的内存
* @param[in] length 待发送数据的长度
* @param[in] flags 标志字
* @return
* @retval >0 发送成功对应大小的数据
* @retval =0 socket被关闭
* @retval <0 socket出错
*/
virtual int send(const void* buffer, size_t length, int flags = 0);
/**
* @brief 发送数据
* @param[in] buffers 待发送数据的内存(iovec数组)
* @param[in] length 待发送数据的长度(iovec长度)
* @param[in] flags 标志字
* @return
* @retval >0 发送成功对应大小的数据
* @retval =0 socket被关闭
* @retval <0 socket出错
*/
virtual int send(const iovec* buffers, size_t length, int flags = 0);
/**
* @brief 发送数据
* @param[in] buffer 待发送数据的内存
* @param[in] length 待发送数据的长度
* @param[in] to 发送的目标地址
* @param[in] flags 标志字
* @return
* @retval >0 发送成功对应大小的数据
* @retval =0 socket被关闭
* @retval <0 socket出错
*/
virtual int sendTo(const void* buffer, size_t length, const Address::ptr to, int flags = 0);
/**
* @brief 发送数据
* @param[in] buffers 待发送数据的内存(iovec数组)
* @param[in] length 待发送数据的长度(iovec长度)
* @param[in] to 发送的目标地址
* @param[in] flags 标志字
* @return
* @retval >0 发送成功对应大小的数据
* @retval =0 socket被关闭
* @retval <0 socket出错
*/
virtual int sendTo(const iovec* buffers, size_t length, const Address::ptr to, int flags = 0);
/**
* @brief 接受数据
* @param[out] buffer 接收数据的内存
* @param[in] length 接收数据的内存大小
* @param[in] flags 标志字
* @return
* @retval >0 接收到对应大小的数据
* @retval =0 socket被关闭
* @retval <0 socket出错
*/
virtual int recv(void* buffer, size_t length, int flags = 0);
/**
* @brief 接受数据
* @param[out] buffers 接收数据的内存(iovec数组)
* @param[in] length 接收数据的内存大小(iovec数组长度)
* @param[in] flags 标志字
* @return
* @retval >0 接收到对应大小的数据
* @retval =0 socket被关闭
* @retval <0 socket出错
*/
virtual int recv(iovec* buffers, size_t length, int flags = 0);
/**
* @brief 接受数据
* @param[out] buffer 接收数据的内存
* @param[in] length 接收数据的内存大小
* @param[out] from 发送端地址
* @param[in] flags 标志字
* @return
* @retval >0 接收到对应大小的数据
* @retval =0 socket被关闭
* @retval <0 socket出错
*/
virtual int recvFrom(void* buffer, size_t length, Address::ptr from, int flags = 0);
/**
* @brief 接受数据
* @param[out] buffers 接收数据的内存(iovec数组)
* @param[in] length 接收数据的内存大小(iovec数组长度)
* @param[out] from 发送端地址
* @param[in] flags 标志字
* @return
* @retval >0 接收到对应大小的数据
* @retval =0 socket被关闭
* @retval <0 socket出错
*/
virtual int recvFrom(iovec* buffers, size_t length, Address::ptr from, int flags = 0);
// 输出信息到流中
virtual std::ostream& dump(std::ostream& os) const;
virtual std::string toString() const;
bool cancelRead(); // 取消读
bool cancelWrite(); // 取消写
bool cancelAccept(); // 取消accept
bool cancelAll(); // 取消所有事件
protected:
void initSock(); // 设置socket属性
void newSock(); // 创建socket m_sockfd = socket()
virtual bool init(int sock); // 初始化sock,调用initSock
protected:
int m_sockfd; /// socket句柄
int m_family; /// 协议簇
int m_type; /// 类型
int m_protocol; /// 协议
bool m_isConnected; /// 是否连接
Address::ptr m_localAddress; /// 本地地址
Address::ptr m_remoteAddress; /// 远端地址
};
// 流式输出socket
std::ostream& operator<<(std::ostream& os, const Socket& sock);
}