day16-重构核心库、使用智能指针
今天是该项目开源在gthub的最后一天,我这里只是将我自己对于这个项目的理解进行总结,如有错误敬请包含指正,今天会整体理一遍代码,并使用智能指针管理整个项目。
1、common
头文件
定义宏用于禁用类的拷贝构造函数、拷贝赋值运算符、移动构造函数和移动赋值运算符。这里注意对右值引用、左值引用、万能引用的理解。
之后这里定义了一些状态,用以防止在发生错误时直接崩溃(这样的程序不够健壮):
RC_UNDEFINED:未定义的状态。
RC_SUCCESS:成功状态。
RC_SOCKET_ERROR:套接字错误。
RC_POLLER_ERROR:轮询器错误。
RC_CONNECTION_ERROR:连接错误。
RC_ACCEPTOR_ERROR:接收器错误。
RC_UNIMPLEMENTED:未实现的功能。
#define DISALLOW_COPY(cname) \
cname(const cname &) = delete; \
cname &operator=(const cname &) = delete;
#define DISALLOW_MOVE(cname) \
cname(cname &&) = delete; \
cname &operator=(cname &&) = delete;
#define DISALLOW_COPY_AND_MOVE(cname) \
DISALLOW_COPY(cname); \
DISALLOW_MOVE(cname);
enum RC {
RC_UNDEFINED,
RC_SUCCESS,
RC_SOCKET_ERROR,
RC_POLLER_ERROR,
RC_CONNECTION_ERROR,
RC_ACCEPTOR_ERROR,
RC_UNIMPLEMENTED
};
2、Socket

在这里我们仅完成服务端的socket、bind、listen以及accept,客户端的socket以及connect。
头文件
首先在头文件中禁用了类的拷贝构造函数、拷贝赋值运算符、移动构造函数和移动赋值运算符。之后依此就是构造析构函数,设置套接字文件描述符 fd_ 的值,返回当前套接字文件描述符 fd_ 的值,获取与当前连接的对端地址,获取 socket 接收缓冲区中的数据大小,创建 socket,绑定 socket 到指定的 IP 和端口,将 socket 设置为监听状态,接受客户端连接请求,发起与服务器的连接请求,设置 socket 为非阻塞模式,检查 socket 是否为非阻塞模式。
class Socket {
public:
DISALLOW_COPY_AND_MOVE(Socket);
Socket();
~Socket();
void set_fd(int fd);
int fd() const;
std::string get_addr() const;
RC Create();
RC Bind(const char *ip, uint16_t port) const;
RC Listen() const;
RC Accept(int &clnt_fd) const;
RC Connect(const char *ip, uint16_t port) const;
RC SetNonBlocking() const;
bool IsNonBlocking() const;
size_t RecvBufSize() const;
private:
int fd_;
};
实现
实现上我们一步一步来看如何完成的。
构造析构函数,没啥好说的对属性初始化和释放资源:
Socket::Socket() : fd_(-1) {
}
Socket::~Socket() {
if (fd_ != -1) {
close(fd_);
fd_ = -1;
}
}
设置获取fd_属性:
void Socket::set_fd(int fd) {
fd_ = fd; }
int Socket::fd() const {
return fd_; }
获取与当前连接的对端地址,getpeername用来获取与某个套接字关联的外地协议地址。
std::string Socket::get_addr() const {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
socklen_t len = sizeof(addr);
if (getpeername(fd_, (struct sockaddr *)&addr, &len) == -1) {
return "";
}
std::string ret(inet_ntoa(addr.sin_addr));
ret += ":";
ret += std::to_string(htons(addr.sin_port));
return ret;
}
接下来是将socket设置为无阻塞模式以及判断是否为无阻塞状态,首先通过fcntl(fd_, F_GETFL)获取socket的属性并设置为O_NONBLOCK,之后将socket通过fcntl(fd_, F_SETFL, …)写入到属性中。
RC Socket::SetNonBlocking() const {
if (fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL) | O_NONBLOCK) == -1) {
perror("Socket set non-blocking failed");
return RC_SOCKET_ERROR;
}
return RC_SUCCESS

最低0.47元/天 解锁文章
494

被折叠的 条评论
为什么被折叠?



