day14-完善Connection类
在之前的编写中,服务器只能完成单一任务,今天我们将改写服务器为一个能够由用户自定义业务的通用网络库。
今天的任务主要在Connection中完成,并且今天我们要将项目整体展示出来(之前将业务工程化后,对于读者项目整体变得不清晰了)。
1、错误检测机制
//声明
void ErrorIf(bool condition, const char *msg);
//实现
void ErrorIf(bool condition, const char *errmsg) {
if (condition) {
perror(errmsg);
exit(EXIT_FAILURE);
}
}
2、Macros
定义了一些宏,用以控制类是否可移动复制等操作。
ASSERT(expr, message):如果expr的值为false,则打印信息message。
UNREACHABLE(message):表示某个程序路径是不可达的,即程序不应该执行到这个位置,如果达到了则抛出错误并打印信息message。
#define DISALLOW_COPY(cname) \
cname(const cname &) = delete; /* NOLINT */ \
cname &operator=(const cname &) = delete; /* NOLINT */
#define DISALLOW_MOVE(cname) \
cname(cname &&) = delete; /* NOLINT */ \
cname &operator=(cname &&) = delete; /* NOLINT */
#define DISALLOW_COPY_AND_MOVE(cname) \
DISALLOW_COPY(cname); \
DISALLOW_MOVE(cname);
#define ASSERT(expr, message) assert((expr) && (message))
#define UNREACHABLE(message) throw std::logic_error(message)
3、Socket
在之前的工作中,我们将地址创建同Socket创建放到了一个文件中,通过声明查看发现本次多了一个Connect的重写以及IsNonBlocking方法。注意,这两个类都是禁止复制移动的,这样可以提高调用效率。
class InetAddress {
public:
InetAddress();
InetAddress(const char *ip, uint16_t port);
~InetAddress() = default;
DISALLOW_COPY_AND_MOVE(InetAddress);
void SetAddr(sockaddr_in addr);
sockaddr_in GetAddr();
const char *GetIp();
uint16_t GetPort();
private:
struct sockaddr_in addr_ {
};
};
class Socket {
private:
int fd_{
-1};
public:
Socket();
explicit Socket(int fd);
~Socket();
DISALLOW_COPY_AND_MOVE(Socket);
void Bind(InetAddress *addr);
void Listen();
int Accept(InetAddress *addr);
void Connect(InetAddress *addr);
void Connect(const char *ip, uint16_t port);
void SetNonBlocking();
bool IsNonBlocking();
int GetFd();
};
之后我们通过实现的代码来理解发生了哪些变化以及多了那些能力。首先在实现中看到的是IsNonBlocking方法,这个方法是用来检查Socket是否是非阻塞模式,是的话返回true;接下来是void Connect(const char *ip, uint16_t port)方法,从实现来看该方法将创建地址同创建Socket做了结合。
Socket::Socket() {
fd_ = socket(AF_INET, SOCK_STREAM, 0);
ErrorIf(fd_ == -1, "socket create error");
}
Socket::Socket(int fd) : fd_(fd) {
ErrorIf(fd_ == -1, "socket create error"); }
Socket::~Socket() {
if (fd_ != -1) {
close(fd_);
fd_ = -1;
}
}
void Socket::Bind(InetAddress *addr) {
struct sockaddr_in tmp_addr = addr->GetAddr();
ErrorIf(bind(fd_, (sockaddr *)&tmp_addr, sizeof(tmp_addr)) == -1, "socket bind error");
}
void Socket::Listen() {
ErrorIf(::listen(fd_, SOMAXCONN) == -1, "socket listen error"); }
void Socket::SetNonBlocking() {
fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL) | O_NONBLOCK); }
bool Socket::IsNonBlocking() {
return (fcntl(fd_, F_GETFL) & O_NONBLOCK) != 0; }
int Socket::Accept(InetAddress *addr) {
// for server socket
int clnt_sockfd = -1;
struct sockaddr_in tmp_addr {
};
socklen_t addr_len = sizeof(tmp_addr);
if (IsNonBlocking()) {
while (true) {
clnt_sockfd = accept(fd_, (sockaddr *)&tmp_addr, &addr_len);
if (clnt_sockfd == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
// printf("no connection yet\n");
continue;
}
if (clnt_sockfd == -1) {
ErrorIf(true, "socket accept error");
} else {
break;
}
}
} else {
clnt_sockfd = accept(fd_, (sockaddr *)&tmp_addr, &addr_len);
ErrorIf(clnt_sockfd == -1, "socket accept error");
}
addr->SetAddr(tmp_addr);
return clnt_sockfd;
}
void Socket::Connect(InetAddress *addr) {
// for client socket
struct sockaddr_in tmp_addr = addr->GetAddr();
if (fcntl(fd_, F_GETFL) & O_NONBLOCK) {
while (true) {
int ret = connect(fd_, (sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret == 0) {
break;
}
if (ret == -1 && (errno == EINPROGRESS)) {
continue;
}
if (ret == -1) {
ErrorIf(true, "socket connect error");
}
}
} else {
ErrorIf(connect(fd_, (sockaddr *)&tmp_addr, sizeof(tmp_addr)) == -1, "socket connect error");
}
}
void Socket::Connect(const char *ip, uint16_t port) {
InetAddress *addr = new InetAddress(ip, port);
Connect(addr);
delete addr;
}
int Socket::GetFd() {
return fd_; }
InetAddress::InetAddress() = default;
InetAddress::InetAddress(const char *ip, uint16_t port) {
memset(&addr_, 0, sizeof(addr_));
addr_.sin_family = AF_INET;
addr_.sin_addr.s_addr = inet_addr(ip);
addr_.sin_port = htons(port);
}
void InetAddress::SetAddr(sockaddr_in addr) {
addr_ = addr; }
sockaddr_in InetAddress::GetAddr() {
return addr_; }
const char *InetAddress::GetIp() {
return inet_ntoa(addr_.sin_addr); }
uint16_t InetAddress::

最低0.47元/天 解锁文章

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



