找工作小项目:day16-重构核心库、使用智能指针(1)

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值