Socket模块
上一章我们将网络编程使用频率非常高的地址封装到了Address
模块中,但是Berkeley
套接字接口也是非常多,并且属于面向过程编程。为了进一步降低网络编程门槛,我们将套接字涉及的接口和状态封装到一个对象中。Socket
模块因此诞生。
github
https://github.com/huxiaohei/tiger.git
实现
Socket
保存了套接字如下信息- 文件描述符
m_sock
- 地址类型
m_family
(AF_INET
、AF_INET6
) - 套接字类型(
SOCK_STREAM
、SOCK_DGRAM
) - 是否链接
m_is_connected
- 本地地址
m_local_addr
- 远程地址
m_remote_addr
- 文件描述符
Socket
提供如下方法- 提供快速创建各种类型的套接字对象的方法
- 设置套接字选项,比如超时等
- 实现绑定地址
bind
、发起连接cinnect
、监听listen
、关闭close
功能 - 实现
accept
方法返回Socket
对象 - 实现套接字对象发送、接收消息
- 提供套接字取消读写以及取消
accept
接口
Socket
借助我们前面实现的FDManager
、IOManager
、Hook
等模块,让同步代码实现异步能力
class Socket : public std::enable_shared_from_this<Socket> {
protected:
int m_sock;
int m_family;
int m_type;
int m_protocol;
bool m_is_connected;
Address::ptr m_local_addr;
Address::ptr m_remote_addr;
protected:
virtual bool init(int sock);
void init_sock();
void new_sock();
Address::ptr init_local_address();
Address::ptr init_remote_address();
public:
typedef std::shared_ptr<Socket> ptr;
Socket(int family, int type, int protocol = 0);
virtual ~Socket();
Socket(const Socket &) = delete;
Socket(const Socket &&) = delete;
Socket &operator=(const Socket &) = delete;
public:
static Socket::ptr CreateTCP(tiger::Address::ptr address);
static Socket::ptr CreateUDP(tiger::Address::ptr address);
static Socket::ptr CreateTCPSocket();
static Socket::ptr CreateUDPSocket();
static Socket::ptr CreateTCPSocket6();
static Socket::ptr CreateUDPSocket6();
static Socket::ptr CreateUnixTCPSocket();
static Socket::ptr CreateUnixUDPSocket();
public:
int get_family() const { return m_family; }
int get_type() const { return m_type; }
int get_protocol() const { return m_protocol; }
bool is_connected() const { return m_is_connected; }
bool is_valid() const { return m_sock != -1; }
int get_socket() const { return m_sock; }
virtual std::ostream &dump(std::ostream &os) const;
virtual std::string to_string() const;
public:
int get_error();
int64_t get_send_timeout();
void set_send_timeout(int64_t timeout);
int64_t get_recv_timeout();
void set_recv_timeout(int64_t timeout);
Address::ptr get_local_addr();
Address::ptr get_remote_addr();
bool get_option(int level, int optname, void *optval, socklen_t *optlen);
bool set_option(int level, int optname, const void *optval, socklen_t optlen);
virtual bool connect(const Address::ptr addr, uint64_t timeout_ms = -1);
virtual bool reconnect(const uint64_t timeout_ms = -1);
virtual bool bind(const Address::ptr addr);
virtual bool listen(int backlog = SOMAXCONN);
virtual Socket::ptr accept();
virtual bool close();
virtual int send(const void *buffer, size_t len, int flags = 0);
virtual int send(const iovec *buffers, size_t len, int flags = 0);
virtual int send_to(const void *buffer, size_t len, const Address::ptr to, int flags = 0);
virtual int send_to(const iovec *buffers, size_t len, const Address::ptr to, int flags = 0);
virtual int recv(void *buffer, size_t len, int flags = 0);
virtual int recv(iovec *buffers, size_t len, int flags = 0);
virtual int recv_from(void *buffer, size_t len, Address::ptr from, int flags = 0);
virtual int recv_from(iovec *buffers, size_t len, Address::ptr from, int flags = 0);
public:
bool cancel_read();
bool cancel_write();
bool cancel_accept();
bool cancel_all();
public:
friend std::ostream &operator<<(std::ostream &os, const Socket::ptr socket);
friend std::ostream &operator<<(std::ostream &os, const Socket &socket);
};
有了以上一系列模块的实现,我们网络编程会变的相对简单很多
void test_socket_send(const std::string &host, tiger::IOManager::ptr iom) {
tiger::IPAddress::ptr addr = tiger::IPAddress::LookupAny(host);
tiger::Socket::ptr socket = tiger::Socket::CreateTCPSocket();
if (!socket->connect(addr)) {
TIGER_LOG_E(tiger::TEST_LOG) << "[socket connnect fail errno:" << strerror(errno) << "]";
return;
}
const char buffer[] = "GET / HTTP/1.0\r\n\r\n";
ssize_t rt = socket->send(buffer, sizeof(buffer));
if (rt <= 0) {
TIGER_LOG_E(tiger::TEST_LOG) << "[socket send fail connected:" << socket->is_connected()
<< " errno:" << strerror(errno) << "]";
return;
}
std::string buffs;
buffs.resize(4096);
rt = socket->recv(&buffs[0], buffs.size());
if (rt <= 0) {
TIGER_LOG_E(tiger::TEST_LOG) << "socket recv fail connected:" << socket->is_connected()
<< " errno:" << strerror(errno) << "]";
return;
}
buffs.resize(rt);
TIGER_LOG_D(tiger::TEST_LOG) << "socket recv:" << buffs;
iom->stop();
}
int main() {
tiger::SingletonLoggerMgr::Instance()->add_loggers("tiger", "../conf/tiger.yml");
tiger::Thread::SetName("Socket");
TIGER_LOG_D(tiger::TEST_LOG) << "[socket test start]";
tiger::IOManager::ptr iom = std::make_shared<tiger::IOManager>("Socket", true, 1);
iom->schedule(std::bind(test_socket_send, "www.baidu.com:80", iom));
iom->start();
TIGER_LOG_D(tiger::TEST_LOG) << "[socket test end]";
}
虽然网络编程门槛有所降低,但是还远远没有结束。进一步封装我们留到下一章