在 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));
}