【Muduo】套接字:InetAddress、Socket

在 Muduo中,InetAddress和Socket是偏向底层的两个模块,封装了底层的一些系统调用,提供了好用的接口。

InetAddress

InetAddress通常用于表示一个网络地址。在 Muduo中,它可能是一个类,用于封装 IP 地址和端口号。

  • IP 地址和端口号:使用 sockaddr_in 存储和表示一个 IP 地址(可以是 IPv4 或 IPv6)和一个端口号。
  • 解析地址:可以从字符串形式的 IP 地址和端口号(如 "127.0.0.1:80")解析出 InetAddress对象。
  • 转换为字符串:可以将 InetAddress对象转换回其字符串表示形式。
  • 获取 IP 地址和端口号:可以获取 InetAddress对象中的 IP 地址和端口号。

Socket

Socket是网络编程中的一个基本概念,它代表了一个端点,用于在网络上进行通信。在 Muduo中,Socket是一个类,用于封装底层的 socket 句柄(或文件描述符)和相关的网络操作。

  • 创建和销毁:创建和销毁一个 socket,包括设置 socket 的类型(如 TCP 或 UDP)、地址族(如 IPv4 或 IPv6)等。
  • 绑定和监听:对于服务器端的 socket,可以通过 bindAddress 将其绑定到一个特定的地址和端口,并通过 listen 开始监听连接请求;对于已连接的客户端socket,可以设置其选项。
  • 连接:对于客户端的 socket,可以 accept 连接到服务器端的 socket。
  • 设置选项:可以设置 socket 的各种选项,如超时时间、缓冲区大小等。
  • 关闭:关闭 socket,释放相关资源。

源码

InetAddress.h

#pragma once
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string>
#include <string.h>

// 封装socket地址类型
class InetAddress
{
public:
    explicit InetAddress(uint16_t port = 0, std::string ip = "127.0.0.1");
    explicit InetAddress(const sockaddr_in &addr)
        : addr_(addr)
    {
    }

    std::string toIp() const;
    std::string toIpPort() const;
    uint16_t toPort() const;

    const sockaddr_in *getSockAddr() const { return &addr_; }

    void setSockAddrInet(const sockaddr_in &addr) { addr_ = addr; };

private:
    sockaddr_in addr_;
};

InetAddress.cc

#include "InetAddress.h"

InetAddress::InetAddress(uint16_t port, std::string ip)
{
    memset(&addr_, 0, sizeof(addr_));
    addr_.sin_family = AF_INET;
    addr_.sin_addr.s_addr = inet_addr(ip.c_str()); // 1、将ip地址转为点分十进制的整数表示  2、转为网络字节序
    addr_.sin_port = htons(port); // 本地字节序转为网络字节序
}

std::string InetAddress::toIp() const
{
    char buf[64] = {0};
    //inet_ntop函数用于将网络地址(如IPv4或IPv6地址)从其网络字节序的内部表示形式转换为人类可读的字符串形式
    ::inet_ntop(AF_INET, &addr_.sin_addr, buf, sizeof buf);
    return buf;
}

std::string InetAddress::toIpPort() const
{
    // ip:port
    char buf[64] = {0};
    ::inet_ntop(AF_INET, &addr_.sin_addr, buf, sizeof buf);
    size_t end = strlen(buf);
    uint16_t port = ntohs(addr_.sin_port);

    sprintf(buf+end, ":%u", port);

    return buf;
}

uint16_t InetAddress::toPort() const
{
    uint16_t port = ntohs(addr_.sin_port);
    return port;
}

Socket.h

#pragma once

#include "noncopyable.h"

class InetAddress;

class Socket
{
public:
    Socket(int sockfd)
        : sockfd_(sockfd)
    {
    }
    ~Socket();

    int fd() const { return sockfd_; }

    /// abort if address in use
    void bindAddress(const InetAddress &localaddr);
    /// abort if address in use
    void listen();

    /// On success, returns a non-negative integer that is
    /// a descriptor for the accepted socket, which has been
    /// set to non-blocking and close-on-exec. *peeraddr is assigned.
    /// On error, -1 is returned, and *peeraddr is untouched.
    int accept(InetAddress *peeraddr);

    void shutdownWrite();

    /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm).
    void setTcpNoDelay(bool on);

    /// Enable/disable SO_REUSEADDR
    void setReuseAddr(bool on);

    /// Enable/disable SO_REUSEPORT
    void setReusePort(bool on);

    /// Enable/disable SO_KEEPALIVE
    void setKeepAlive(bool on);

private:
    const int sockfd_;
};

Socket.cc

#include "Socket.h"
#include "InetAddress.h"
#include "LogStream.h"

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "netinet/tcp.h"

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

void Socket::bindAddress(const InetAddress &localaddr)
{
    if (0 != ::bind(sockfd_, (sockaddr *)localaddr.getSockAddr(), sizeof(sockaddr_in)))
    {
        LOG_FATAL << "Socket::bindAddress error, errno: " << errno;
    }
}

void Socket::listen()
{
    LOG_DEBUG << "Socket::listen()";
    // 定义了一个 “等待连接队列” 的最大长度为1024
    // 队列用于存储那些已经到达服务器但尚未被 accept() 系统调用处理的连接请求
    if (0 != ::listen(sockfd_, 1024))
    {
        LOG_FATAL << "Socket::listen error, errno: " << errno;
    }
}

int Socket::accept(InetAddress *peeraddr)
{
    /**
     * 1. accept函数的参数不合法
     * 2. 对返回的connfd没有设置非阻塞
     * Reactor模型:one loop per thread
     * poller + non-blocking IO
    */
    LOG_DEBUG << "Socket::accept(InetAddress *peeraddr) : " << peeraddr->toIpPort();
    sockaddr_in addr;
    socklen_t len = sizeof addr;
    memset(&addr, 0, sizeof addr);
    int connfd = ::accept4(sockfd_, (sockaddr *)&addr, &len, SOCK_NONBLOCK | SOCK_CLOEXEC);
    if (connfd >= 0)
    {
        peeraddr->setSockAddrInet(addr);
    }
    return connfd;
}

void Socket::shutdownWrite()
{
    if (::shutdown(sockfd_, SHUT_WR) < 0)
    {
        LOG_ERROR << "Socket::shutdownWrite() error, errno: " << errno;
    }
}

void Socket::setTcpNoDelay(bool on)
{
    int optval = on ? 1 : 0;
    ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY,
                 &optval, static_cast<socklen_t>(sizeof optval));
}

void Socket::setReuseAddr(bool on)
{
    int optval = on ? 1 : 0;
    ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR,
                 &optval, static_cast<socklen_t>(sizeof optval));
}

void Socket::setReusePort(bool on)
{
    int optval = on ? 1 : 0;
    int ret = ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT,
                           &optval, static_cast<socklen_t>(sizeof optval));
    if (ret < 0 && on)
    {
        LOG_ERROR << "SO_REUSEPORT failed.";
    }
}

void Socket::setKeepAlive(bool on)
{
    int optval = on ? 1 : 0;
    ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE,
                 &optval, static_cast<socklen_t>(sizeof optval));
}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值