sylar高性能服务器-日志(P54-P56)内容记录

P54-P56:Socket 06-08

后面三节内容和前面Address模块一样,主要对socket的方法进行封装,提供接口方便的创建TCPUDPUnixsocket对象。

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

class Socket

成员变量
// socketfd
int m_sock;
// 协议簇
int m_family;
// 类型
int m_type;
// 协议
int m_protocol;
// 是否连接
bool m_isConnected;
// 本地地址
Address::ptr m_localAddress;
// 远端地址
Address::ptr m_remoteAddress;
创建套接字
Socket::ptr Socket::CreateTCP(sylar::Address::ptr address) {
    Socket::ptr sock(new Socket(address->getFamily(), TCP, 0));
    return sock;
}

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

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

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

Socket::ptr Socket::CreateUnixUDPSocket() {
    Socket::ptr sock(new Socket(UNIX, UDP, 0));
    return sock;
}
构造/析构函数
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() {
    close();
}
超时时间
int64_t Socket::getSendTimeout() {
    // 通过句柄管理器获得一个句柄
    FdCtx::ptr ctx = FdMgr::GetInstance()->get(m_sock);
    if(ctx) {
        // 成功获取则调用Fdctx中的获取超时时间函数,根据传入的参数获取接收超时时间或者发送超时时间
        return ctx->getTimeout(SO_SNDTIMEO);
    }
    return -1;
}

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

int64_t Socket::getRecvTimeout() {
    FdCtx::ptr ctx = FdMgr::GetInstance()->get(m_sock);
    if(ctx) {
        return ctx->getTimeout(SO_RCVTIMEO);
    }
    return -1;
}
getOption
bool Socket::getOption(int level, int option, void* result, size_t* len) {
    // 调用之前写的hook函数getsockopt,通过socketfd获取详细信息
    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 << " errstr = " << strerror(errno);
        return false;
    }
    return true;
}
setOption
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 << " errstr = " << strerror(errno);
        return false;
    }
    return true;
}

init
bool Socket::init(int sock) {
    FdCtx::ptr ctx = FdMgr::GetInstance()->get(sock);
    if(ctx && ctx->isSocket() && !ctx->isClose()) {
        m_sock = sock;
        m_isConnected = true;
        initSock();
        getLocalAddress();
        getRemoteAddress();
        return true;
    }
    return false;
}
initSock
void Socket::initSock() {
    int val = 1;
    setOption(SOL_SOCKET, SO_REUSEADDR, val);
    if(m_type == SOCK_STREAM) {
        setOption(IPPROTO_TCP, TCP_NODELAY, val);
    }
}
newSock
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 << " errstr = " << 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 << ") addr.family(" << addr->getFamily()
            << ") not equal, addr = " << addr->toString();
        return false;
    }

    if(::bind(m_sock, addr->getAddr(), addr->getAddrLen())) {
        SYLAR_LOG_ERROR(g_logger) << "bind error 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
            << " errstr = " << strerror(errno);
        return false;
    }
    return true;
}
accept
Socket::ptr Socket::accept() {
    // 创建新的socket对象,用于与客户端通信。
    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 << " errstr = " << 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) << "connect sock.family("
            << m_family << ") addr.family(" << addr->getFamily()
            << ") not equal, 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 << " errstr = " << 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()
                << ") tomeout" << timeout_ms << " error errno = " << errno << " errstr = " << strerror(errno);
            close();
            return false;
        }
    }
    m_isConnected = true;
    getRemoteAddress();
    getLocalAddress();
    return true;
}
close
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 false;
}
发送数据
int Socket::send(const void* buffer, size_t length, int flag) {
    if(isConnected()) {
        return ::send(m_sock, buffer, length, flag);
    }
    return -1;
}

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

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

int Socket::sendTo(const iovec* buffers, size_t length, const Address::ptr to,int flag) {
    if(isConnected()) {
        msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = (iovec*)buffers;
        msg.msg_iovlen = length;
        msg.msg_name = to->getAddr();
        msg.msg_namelen = to->getAddrLen();
        return ::sendmsg(m_sock, &msg, flag);
    }
    return -1;
}
接收数据
int Socket::recv(void* buffer, size_t length, int flag) {
    if(isConnected()) {
        return ::recv(m_sock, buffer, length,flag);
    }
    return -1;
}

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

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, from->getAddr(), &len);
    }
    return -1;
}

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 = from->getAddr();
        msg.msg_namelen = from->getAddrLen();
        return ::recvmsg(m_sock, &msg, flags);
    }
    return -1;
}
getRemoteAddress
Address::ptr Socket::getRemoteAddress() {
    // 已经有了直接返回
    if(m_remoteAddress) {
        return m_remoteAddress;
    }
    // 结果地址
    Address::ptr result;
    // 根据协议簇创建指定地址
    switch(m_family) {
        case AF_INET:
            result.reset(new IPv4Address());
            break;
        case AF_INET6:
            result.reset(new IPv6Address());
        case AF_UNIX:
            result.reset(new UnixAddress());
            break;
        default:
            result.reset(new UnknownAddress(m_family));
            break;
    }
    // 获取地址长度
    socklen_t addrlen = result->getAddrLen();
    if(getpeername(m_sock, result->getAddr(), &addrlen)) {
        SYLAR_LOG_ERROR(g_logger) << "getpeername error sock = " << m_sock
            << " errno = " << errno << " errstr = " << strerror(errno);
        return Address::ptr(new UnknownAddress(m_family));
    }
    if(m_family == AF_UNIX) {
        UnixAddress::ptr addr = std::dynamic_pointer_cast<UnixAddress>(result);
        addr->setAddrLen(addrlen);
    }
    m_remoteAddress = result;
    return m_remoteAddress;
}
getLocalAddress
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());
        case AF_UNIX:
            result.reset(new UnixAddress());
            break;
        default:
            result.reset(new UnknownAddress(m_family));
            break;
    }
    socklen_t addrlen = result->getAddrLen();
    if(getsockname(m_sock, result->getAddr(), &addrlen)) {
        SYLAR_LOG_ERROR(g_logger) << "getsockname error sock = " << m_sock
            << " errno = " << errno << " errstr = " << strerror(errno);
        return Address::ptr(new UnknownAddress(m_family));
    }
    if(m_family == AF_UNIX) {
        UnixAddress::ptr addr = std::dynamic_pointer_cast<UnixAddress>(result);
        addr->setAddrLen(addrlen);
    }
    m_localAddress = result;
    return m_localAddress;
}

测试

代码

#include "../sylar/socket.h"
#include "../sylar/sylar.h"
#include "../sylar/iomanager.h"
#include "../sylar/address.h"

static sylar::Logger::ptr g_looger = SYLAR_LOG_ROOT();

void test_socket() {
    sylar::IPAddress::ptr addr = sylar::Address::LookupAnyIPAdress("www.baidu.com");
    if(addr) {
        SYLAR_LOG_INFO(g_looger) << "get address: " << addr->toString();
    } else {
        SYLAR_LOG_ERROR(g_looger) << "get address fail";
        return;
    }

    sylar::Socket::ptr sock = sylar::Socket::CreateTCP(addr);
    addr->setPort(80);
    if(!sock->connect(addr)) {
        SYLAR_LOG_ERROR(g_looger) << "connect " << addr->toString() << " fail";
        return;
    } else {
        SYLAR_LOG_INFO(g_looger) << "connect " << addr->toString() << " connected";
    }
    const char buff[] = "GET / HTTP/1.0\r\n\r\n";
    int rt = sock->send(buff, sizeof(buff));
    if(rt <= 0) {
        SYLAR_LOG_ERROR(g_looger) << "send fail rt = " << rt;
        return;
    }

    std::string buffs;
    buffs.resize(4096);
    rt = sock->recv(&buffs[0], buffs.size());

    if(rt <= 0) {
        SYLAR_LOG_ERROR(g_looger) << "recv fail rt = " << rt;
        return;
    }

    buffs.resize(rt);
    SYLAR_LOG_INFO(g_looger) << buffs;
}

int main(int argc, char** argv) {
    sylar::IOManager iom;
    iom.schedule(&test_socket);
    return 0;
}

结果

image-20240305151152605

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

madkeyboard

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值