[sylar]C++高性能服务器框架——Socket模块

705 阅读4分钟

Socket模块概述

主要对socket的方法进行封装,提供接口方便的创建TCPUDPUnixsocket对象。

当创建一个socket对象时,并没有真正的创建一个socket句柄,此时它的句柄为-1,只有在bindconnect的时候才会通过newSock()创建一个socket句柄与对象关联起来,在accept时创建新的socket对象,并初始化。新的socket句柄都初始化为地址复用模式,如果为TCP连接,禁用Nagle算法,提高传输效率,降低延迟。

详解

class Socket

socket类型

enum Type {
    TCP = SOCK_STREAM,
    UDP = SOCK_DGRAM
};

协议簇

enum Family {
    IPv4 = AF_INET,
    IPv6 = AF_INET6,
    UNIX = AF_UNIX
};

mumber(成员变量)

// socketfd
int m_sock;
// 协议簇
int m_family;
// 类型
int m_type;
// 协议
int m_protocol;
// 是否连接
bool m_isConnected;
// 本地地址
Address::ptr m_localAddress;
// 远端地址
Address::ptr m_remotrAddress;

CreateTCP(根据地址创建TCP套接字)

静态方法

Socket::ptr Socket::CreateTCP(sylar::Address::ptr address) {
    Socket::ptr sock(new Socket(address->getFamily(), TCP, 0));
    return sock;
}

CreateUDP(根据地址创建UDP套接字)

静态方法

Socket::ptr Socket::CreateUDP(sylar::Address::ptr address) {
    Socket::ptr sock(new Socket(address->getFamily(), UDP, 0));
    return sock;
}

CreateTCPSocket(创建IPv4TCP套接字)

静态方法

Socket::ptr Socket::CreateTCPSocket() {
    Socket::ptr sock(new Socket(IPv4, TCP, 0));
    return sock;
}

CreateUDPSocket(创建IPv4UDP套接字)

静态方法

Socket::ptr Socket::CreateUDPSocket() {
    Socket::ptr sock(new Socket(IPv4, UDP, 0));
    return sock;
}

CreateTCPSocket6(创建IPv6TCP套接字)

静态方法

Socket::ptr Socket::CreateTCPSocket6() {
    Socket::ptr sock(new Socket(IPv6, TCP, 0));
    return sock;
}

CreateUDPSocket6(创建IPv6UDP套接字)

静态方法

Socket::ptr Socket::CreateUDPSocket6() {
    Socket::ptr sock(new Socket(IPv6, UDP, 0));
    return sock;
}

CreateTCPSocket6(创建UnixTCP套接字)

静态方法

Socket::ptr Socket::CreateUnixTCPSocket() {
    Socket::ptr sock(new Socket(UNIX, TCP, 0));
    return sock;   
}

CreateUDPSocket6(创建UnixUDP套接字)

静态方法

Socket::ptr Socket::CreateUnixUDPSocket() {
    Socket::ptr sock(new Socket(UNIX, UDP, 0));
    return sock;     
}

Socket(构造函数)

只是创建对象,并没有真正的创建socketfd

Socket::Socket(int family, int type, int protocol)
    :m_sock(-1)
    ,m_family(family)
    ,m_type(type)
    ,m_protocol(protocol)
    ,m_isConnected(false) {
        
}

~Socket(析构函数)

Socket::~Socket() {
    close();
}

getSendTimeout(返回发送超时时间)

int64_t Socket::getSendTimeout() {
    sylar::FdCtx::ptr ctx = sylar::FdMgr::GetInstance()->get(m_sock);
    if (ctx) {
        return ctx->getTimeout(SO_SNDTIMEO);
    }
    return -1;
}

setSendTimeout(设置发送超时时间)

void Socket::setSendTimeout(int64_t v) {
    struct timeval tv { int(v / 1000), int(v % 1000 * 1000) };
    setOption(SOL_SOCKET, SO_SNDTIMEO, tv);

}

getRecvTimeout(返回接收超时时间)

int64_t Socket::getRecvTimeout() {
    sylar::FdCtx::ptr ctx = sylar::FdMgr::GetInstance()->get(m_sock);
    if (ctx) {
        return ctx->getTimeout(SO_RCVTIMEO);
    }
    return -1;
}

setRecvTimeout(设置接收超时时间)

void Socket::setRecvTimeout(int64_t v) {
    struct timeval tv { int(v / 1000), int(v % 1000) * 1000 };
    setOption(SOL_SOCKET, SO_RCVTIMEO, tv);
}

getOption(获取socketfd信息)

模板函数

template<class T>
bool getOption(int level, int option, T& result) {
    size_t length = sizeof(T);
    return getOption(level, option, &result, &length);
}
bool Socket::getOption(int level, int option, void* result, size_t* len) {
    int rt = getsockopt(m_sock, level, option, result, (socklen_t*)len);
    if (rt) {
        SYLAR_LOG_DEBUG(g_logger) << "getOption sock = " << m_sock
            << ", level = " << level << ", option = " << option
            << ", errno = " << errno << ", strerr = " << strerror(errno);
        return false;
    }
    return true;
}

getOption(设置socketfd信息)

模板函数

template<class T>
bool setOption(int level, int option, const T& result) {
    return setOption(level, option, &result, sizeof(T));
}
bool Socket::setOption(int level, int option, const void* result, size_t len) {
    int rt = setsockopt(m_sock, level, option, result, (socklen_t)len);
    if (rt) {
        SYLAR_LOG_DEBUG(g_logger) << "setOption sock = " << m_sock
            << ", level = " << level << ", option = " << option
            << ", errno = " << errno << ", strerr = " << strerror(errno);
        return false;
    }
    return true;
}

init(初始化socket对象)

private

初始化accept后用于通信的socket

bool Socket::init(int sock) {
    FdCtx::ptr ctx = sylar::FdMgr::GetInstance()->get(sock);
    if (ctx && ctx->isSocket() && !ctx->isClosed()) {
        m_sock = sock;
        m_isConnected = true;
        initSock();
        getLocalAddress();
        getRemoteAddress();
        return true;
    }
    return false;
}

initSock(初始化socketfd)

private

void Socket::initSock() {
    int val = 1;
    // SO_REUSEADDR 打开或关闭地址复用功能 option_value不等于0时,打开
    setOption(SOL_SOCKET, SO_REUSEADDR, val);
    if (m_type == SOCK_STREAM) {
        // Nagle算法通过将小数据块合并成更大的数据块来减少网络传输的次数,提高网络传输的效率。
        // 禁用Nagle算法,减小延迟
        setOption(IPPROTO_TCP, TCP_NODELAY, val);
    }
}

newSock(创建socketfd)

private

void Socket::newSock() {
    m_sock = socket(m_family, m_type, m_protocol);
    if (SYLAR_LIKELY(m_sock != -1)) {
        initSock();
    } else {
        SYLAR_LOG_ERROR(g_logger) << "socket(" << m_family
            << ", " << m_type << ", " << m_protocol << ") errno = "
            << errno << ", strerr = " << strerror(errno);
    }
}

bind(绑定地址)

bool Socket::bind(const Address::ptr addr) {
    // 如果没有socketfd
    if (!isValid()) {
        // 创建socketfd
        newSock();
        if (SYLAR_UNLIKELY(!isValid())) {
            return false;
        }
    }

    if (SYLAR_UNLIKELY(addr->getFamily() != m_family)) {
        SYLAR_LOG_ERROR(g_logger) << "bind sock.family("
            << m_family << ") add.family(" << addr->getFamily()
            << ") not qual, addr = " << addr->toString();
        return false;
    }

    if (::bind(m_sock, addr->getAddr(), addr->getAddrLen())) {
        SYLAR_LOG_ERROR(g_logger) << "bind errno = " << errno
            << ", strerr = " << strerror(errno);
        return false;
    }

    getLocalAddress();
    return true;
}

listen(监听)

bool Socket::listen(int backlog) {
    if (!isValid()) {
        SYLAR_LOG_ERROR(g_logger) << "listen error sock = -1";
        return false;
    }

    if (::listen(m_sock, backlog)) {
        SYLAR_LOG_ERROR(g_logger) << "listen error errno = " << errno
            << ", strerr = " << strerror(errno);
        return false;
    }
    return true;
}

accept(接收connect连接)

创建新的socket对象,用于与客户端通信。

Socket::ptr Socket::accept() {
    Socket::ptr sock(new Socket(m_family, m_type, m_protocol));
    int newsock = ::accept(m_sock, nullptr, nullptr);
    if (newsock == -1) {
        SYLAR_LOG_ERROR(g_logger) << "accept(" << m_sock << ") errno = "
            << errno << ", strerr = " << strerror(errno);
        return nullptr;
    }
    if (sock->init(newsock)) {
        return sock;
    }
    return nullptr;
}

connect(连接地址)

bool Socket::connect(const Address::ptr addr, uint64_t timeout_ms) {
    if (!isValid()) {
        newSock();
        if (SYLAR_UNLIKELY(!isValid())) {
            return false;
        }
    }
	
    if (SYLAR_UNLIKELY(addr->getFamily() != m_family)) {
        SYLAR_LOG_ERROR(g_logger) << "bind sock.family("
            << m_family << ") add.family(" << addr->getFamily()
            << ") not qual, addr = " << addr->toString();
        return false;
    }
	
    
    if (timeout_ms == (uint64_t)-1) {
        if (::connect(m_sock, addr->getAddr(), addr->getAddrLen())) {
            SYLAR_LOG_ERROR(g_logger) << "sock = " << m_sock << "connect ("
                << addr->toString() << ") error errno = " << errno
                << ", strerr = " << strerror(errno);
            close();
            return false;
        }
    } else {
        if (::connect_with_timeout(m_sock, addr->getAddr(), addr->getAddrLen(), timeout_ms)) {
            SYLAR_LOG_ERROR(g_logger) << "sock = " << m_sock << "connect ("
                << addr->toString() << ") error errno = " << errno
                << ", strerr = " << strerror(errno);
            close();
            return false;
        }
    }
    m_isConnected = true;
    getRemoteAddress();
    getLocalAddress();
    return true;
}

close(关闭socket)

bool Socket::close() {
    if (!m_isConnected && m_sock == -1) {
        return true;
    }
    m_isConnected = false;
    if (m_sock != -1) {
        ::close(m_sock);
        m_sock = -1;
    }
    return true;
}

send(发送数据:单数据块)

int Socket::send(const void* buffer, size_t length, int flags) {
    if (isConnected()) {
        return ::send(m_sock, buffer, length, flags);
    }
    return -1;
}

send(发送数据:多数据块)

int Socket::send(const iovec* buffers, size_t length, int flags) {
    if (isConnected()) {
        msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = (iovec*)buffers;
        msg.msg_iovlen = length;
        return ::sendmsg(m_sock, &msg, flags);
    }
    return -1;
}

sendTo(指定地址发送数据:单数据块)

int Socket::sendTo(const void* buffer, size_t length, const Address::ptr to, int flags) {
    if (isConnected()) {
        return ::sendto(m_sock, buffer, length, flags, to->getAddr(), to->getAddrLen());
    }
    return -1;
}

sendTo(指定地址发送数据:多数据块)

int Socket::sendTo(const iovec* buffers, size_t length, const Address::ptr to, int flags) {
    if (isConnected()) {
        msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = (iovec*)buffers;
        msg.msg_iovlen = length;
        msg.msg_name = const_cast<sockaddr*>(to->getAddr());
        msg.msg_namelen = to->getAddrLen();

        return ::sendmsg(m_sock, &msg, flags);
    }
    return -1;
}

recv(接收数据:单数据块)

int Socket::recv(void* buffer, size_t length, int flags) {
    if (isConnected()) {
        return ::recv(m_sock, buffer, length, flags);
    }
    return -1;
}

recv(接收数据:多数据块)

int Socket::recv(iovec* buffers, size_t length, int flags) {
    if (isConnected()) {
        msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = (iovec*)buffers;
        msg.msg_iovlen = length;
        return ::recvmsg(m_sock, &msg, flags);
    }
    return -1;
}

recvFrom(指定地址接收数据:单数据块)

int Socket::recvFrom(void* buffer, size_t length, Address::ptr from, int flags) {
    if (isConnected()) {
        socklen_t len = from->getAddrLen();
        return ::recvfrom(m_sock, buffer, length, flags, const_cast<sockaddr*>(from->getAddr()), &len);
    }
    return -1;
}

recvFrom(指定地址接收数据:多数据块)

int Socket::recvFrom(iovec* buffers, size_t length, Address::ptr from, int flags) {
    if (isConnected()) {
        msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = (iovec*)buffers;
        msg.msg_iovlen = length;
        msg.msg_name = const_cast<sockaddr*>(from->getAddr());
        msg.msg_namelen = from->getAddrLen();

        return recvmsg(m_sock, &msg, flags);
    }
    return -1;
}

getRemoteAddress(返回远端地址)

Address::ptr Socket::getRemoteAddress() {
    if (m_remotrAddress) {
        return m_remotrAddress;
    }

    Address::ptr result;
    switch (m_family) {
        case AF_INET:
            result.reset(new IPv4Address());
            break;
        case AF_INET6:
            result.reset(new IPv6Address());
            break;
        case AF_UNIX:
            result.reset(new UinxAddress());
            break;
        default:
            result.reset(new UnknowAddress(m_family));
            break;
    }
    socklen_t addrlen = result->getAddrLen();
    // 获取一个已连接套接字的远程地址信息
    if (getpeername(m_sock, const_cast<sockaddr*>(result->getAddr()), &addrlen)) {
        SYLAR_LOG_ERROR(g_logger) << "getpeername error sock = " << m_sock
             << ", errno = " << errno << ", strerr = " << strerror(errno);
        return Address::ptr(new UnknowAddress(m_family));
    }

    if (m_family == AF_UNIX) {
        UinxAddress::ptr addr = std::dynamic_pointer_cast<UinxAddress>(result);
        addr->setAddrlen(addrlen);
    }
    m_remotrAddress = result;
    return m_remotrAddress;
}

getRemoteAddress(返回本地地址)

Address::ptr Socket::getLocalAddress() {
    if (m_localAddress) {
        return m_localAddress;
    }

    Address::ptr result;
    switch (m_family) {
        case AF_INET:
            result.reset(new IPv4Address());
            break;
        case AF_INET6:
            result.reset(new IPv6Address());
            break;
        case AF_UNIX:
            result.reset(new UinxAddress());
            break;
        default:
            result.reset(new UnknowAddress(m_family));
            break;
    }
    socklen_t addrlen = result->getAddrLen();
    // 获取一个套接字的本地地址信息
    if (getsockname(m_sock, const_cast<sockaddr*>(result->getAddr()), &addrlen)) {
        SYLAR_LOG_ERROR(g_logger) << "getsockname error sock = " << m_sock
            << ", errno = " << errno << ", strerr = " << strerror(errno);
        return Address::ptr(new UnknowAddress(m_family));
    }

    if (m_family == AF_UNIX) {
        UinxAddress::ptr addr = std::dynamic_pointer_cast<UinxAddress>(result);
        addr->setAddrlen(addrlen);
    }
    m_localAddress = result;
    return m_localAddress;
}

cancelRead(取消读事件)

bool Socket::cancelRead() {
    return IOManager::GetThis()->cancelEvent(m_sock, sylar::IOManager::READ);
}

cancelWrite(取消写事件)

bool Socket::cancelWrite() {
    return IOManager::GetThis()->cancelEvent(m_sock, sylar::IOManager::WRITE);
}

cancelAccept(取消accept)

bool Socket::cancelAccept() {
    return IOManager::GetThis()->cancelEvent(m_sock, sylar::IOManager::READ);
}

cancelAll(取消所有事件)

bool Socket::cancelAll() {
    return IOManager::GetThis()->cancelAll(m_sock);
}