赞
踩
Acceptor模块是为了创建套接字,并且接收新到来的客户端套接字,将对应套接字的Channel对象添加到Poller对象中,进行事件监控。
在构造函数这里,就对主线程上面的网络套接字进行回调函数的设置。
会在TcpServer模块中,启动该套接字读事件监控,并将对应的Channel对象添加到Poller对象中。
由上面代码可以看出,服务器端网络套接字的创建,就是对服务端指定的端口进行监听,这个地址是不能固定的,因为一个端口有可能有几个网卡,服务器不知道要监听那个网卡。于是,服务端一般就是,任意地址,让服务器监听这个端口上的所有网卡。
- #define MAX_LISTEN 1024
- class Socket {
- private:
- int _sockfd;
- public:
- Socket():_sockfd(-1) {}
- Socket(int fd): _sockfd(fd) {}
- ~Socket() { Close(); }
- int Fd() { return _sockfd; }
- //创建套接字
- bool Create() {
- // int socket(int domain, int type, int protocol)
- _sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (_sockfd < 0) {
- ERR_LOG("CREATE SOCKET FAILED!!");
- return false;
- }
- return true;
- }
- //绑定地址信息
- bool Bind(const std::string &ip, uint16_t port) {
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = inet_addr(ip.c_str());
- socklen_t len = sizeof(struct sockaddr_in);
- // int bind(int sockfd, struct sockaddr*addr, socklen_t len);
- int ret = bind(_sockfd, (struct sockaddr*)&addr, len);
- if (ret < 0) {
- ERR_LOG("BIND ADDRESS FAILED!");
- return false;
- }
- return true;
- }
- //开始监听
- bool Listen(int backlog = MAX_LISTEN) {
- // int listen(int backlog)
- int ret = listen(_sockfd, backlog);
- if (ret < 0) {
- ERR_LOG("SOCKET LISTEN FAILED!");
- return false;
- }
- return true;
- }
- //向服务器发起连接
- bool Connect(const std::string &ip, uint16_t port) {
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = inet_addr(ip.c_str());
- socklen_t len = sizeof(struct sockaddr_in);
- // int connect(int sockfd, struct sockaddr*addr, socklen_t len);
- int ret = connect(_sockfd, (struct sockaddr*)&addr, len);
- if (ret < 0) {
- ERR_LOG("CONNECT SERVER FAILED!");
- return false;
- }
- return true;
- }
- //获取新连接
- int Accept() {
- // int accept(int sockfd, struct sockaddr *addr, socklen_t *len);
- int newfd = accept(_sockfd, NULL, NULL);
- if (newfd < 0) {
- ERR_LOG("SOCKET ACCEPT FAILED!");
- return -1;
- }
- return newfd;
- }
- //接收数据
- ssize_t Recv(void *buf, size_t len, int flag = 0) {
- // ssize_t recv(int sockfd, void *buf, size_t len, int flag);
- ssize_t ret = recv(_sockfd, buf, len, flag);
- if (ret <= 0) {
- //EAGAIN 当前socket的接收缓冲区中没有数据了,在非阻塞的情况下才会有这个错误
- //EINTR 表示当前socket的阻塞等待,被信号打断了,
- if (errno == EAGAIN || errno == EINTR) {
- return 0;//表示这次接收没有接收到数据
- }
- ERR_LOG("SOCKET RECV FAILED!!");
- return -1;
- }
- return ret; //实际接收的数据长度
- }
- ssize_t NonBlockRecv(void *buf, size_t len) {
- return Recv(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT 表示当前接收为非阻塞。
- }
- //发送数据
- ssize_t Send(const void *buf, size_t len, int flag = 0) {
- // ssize_t send(int sockfd, void *data, size_t len, int flag);
- ssize_t ret = send(_sockfd, buf, len, flag);
- if (ret < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- return 0;
- }
- ERR_LOG("SOCKET SEND FAILED!!");
- return -1;
- }
- return ret;//实际发送的数据长度
- }
- ssize_t NonBlockSend(void *buf, size_t len) {
- if (len == 0) return 0;
- return Send(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT 表示当前发送为非阻塞。
- }
- //关闭套接字
- void Close() {
- if (_sockfd != -1) {
- close(_sockfd);
- _sockfd = -1;
- }
- }
- //创建一个服务端连接
- bool CreateServer(uint16_t port, const std::string &ip = "0.0.0.0", bool block_flag = false) {
- //1. 创建套接字,2. 绑定地址,3. 开始监听,4. 设置非阻塞, 5. 启动地址重用
- if (Create() == false) return false;
- if (block_flag) NonBlock();
- if (Bind(ip, port) == false) return false;
- if (Listen() == false) return false;
- ReuseAddress();
- return true;
- }
- //创建一个客户端连接
- bool CreateClient(uint16_t port, const std::string &ip) {
- //1. 创建套接字,2.指向连接服务器
- if (Create() == false) return false;
- if (Connect(ip, port) == false) return false;
- return true;
- }
- //设置套接字选项---开启地址端口重用
- void ReuseAddress() {
- // int setsockopt(int fd, int leve, int optname, void *val, int vallen)
- int val = 1;
- setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&val, sizeof(int));
- val = 1;
- setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void*)&val, sizeof(int));
- }
- //设置套接字阻塞属性-- 设置为非阻塞
- void NonBlock() {
- //int fcntl(int fd, int cmd, ... /* arg */ );
- int flag = fcntl(_sockfd, F_GETFL, 0);
- fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK);
- }
- };
- class Acceptor {
- private:
- Socket _socket;//用于创建监听套接字
- EventLoop *_loop; //用于对监听套接字进行事件监控
- Channel _channel; //用于对监听套接字进行事件管理
-
- using AcceptCallback = std::function<void(int)>;
- AcceptCallback _accept_callback;
- private:
- /*监听套接字的读事件回调处理函数---获取新连接,调用_accept_callback函数进行新连接处理*/
- void HandleRead() {
- int newfd = _socket.Accept();
- if (newfd < 0) {
- return ;
- }
- if (_accept_callback) _accept_callback(newfd);
- }
- int CreateServer(int port) {
- bool ret = _socket.CreateServer(port);
- assert(ret == true);
- return _socket.Fd();
- }
- public:
- /*不能将启动读事件监控,放到构造函数中,必须在设置回调函数后,再去启动*/
- /*否则有可能造成启动监控后,立即有事件,处理的时候,回调函数还没设置:新连接得不到处理,且资源泄漏*/
- Acceptor(EventLoop *loop, int port): _socket(CreateServer(port)), _loop(loop),
- _channel(loop, _socket.Fd()) {
- _channel.SetReadCallback(std::bind(&Acceptor::HandleRead, this));
- }
- void SetAcceptCallback(const AcceptCallback &cb) { _accept_callback = cb; }
- void Listen() { _channel.EnableRead(); }
- };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。