作为一个宏大的、功能健全的muduo库,考虑的肯定是众多情况是否可以高效满足;而作为学习者,我们需要抽取其中的精华进行简要实现,这要求我们足够了解muduo库。
做项目 = 模仿 + 修改,不要担心自己学了也不会写怎么办,重要的是积累,学到了这些方法,如果下次在遇到通用需求的时候你能够回想起之前的解决方法就够了。送上一段话!
sockaddr是一个用于存储套接字地址的结构体,它可以表示不同类型的地址,包括IPv4、IPv6等。它通常用于bind、connect、recvfrom和sendto等函数的参数,指明地址信息。然而,sockaddr结构体存在一些弊端,其中最主要的是sa_data字段将目标地址和端口信息混在一起,这导致在使用某些网络函数时需要额外的处理才能正确地获取地址和端口信息。
为了解决sockaddr的缺陷,出现了sockaddr_in结构体。与sockaddr相比,sockaddr_in结构体将port和addr分开储存在两个变量中,分别对应sin_port和sin_addr字段。这种结构使得地址和端口信息更加清晰,易于处理。同时,sockaddr_in结构体还提供了方便的函数来操作地址和端口信息,例如inet_pton和inet_ntop等。
总的来说,sockaddr_in相对于sockaddr具有更加清晰的结构和易于操作的字段,因此在网络编程中通常更受欢迎。虽然sockaddr仍然可以使用,但在处理IPv4地址时建议使用sockaddr_in结构体。
sin_family
sin_addr
sin_port
sin_zero
int inet_aton(const char *cp, struct in_addr *inp);
inet_aton()将Internet主机地址cp从IPv4数字和点符号转换为二进制形式(以网络字节顺序),并将其存储在inp指向的结构中。Inet_aton()如果地址有效则返回非零,如果无效则返回零。
如果提供的字符串被成功解释,Inet_aton()返回1,如果字符串无效(错误时没有设置errno)则返回0。
in_addr_t inet_addr(const char *cp);
inet_addr()函数的作用是:将Internet主机地址cp从IPv4的数字点法转换为网络字节顺序的二进制数据。如果输入无效,则返回INADDR_NONE(通常为-1)。使用这个函数是有问题的,因为-1是一个有效的地址(255.255.255.255)。避免使用它,而应使用inet_aton()、inet_pton(3)或getaddrinfo(3),它们提供了一种更清晰的方式来指示错误返回。
in_addr_t inet_network(const char *cp);
inet_network()函数的作用是将cp (IPv4数字和点表法中的字符串)转换为适合用作Internet网络地址的主机字节顺序的数字。如果成功,则返回转换后的地址。如果输入无效,则返回-1。
char *inet_ntoa(struct in_addr in);
inet_ntoa()函数的作用是:将Internet主机地址(以网络字节顺序给出)转换为IPv4点分十进制格式的字符串。字符串在静态分配的缓冲区中返回,后续调用将覆盖该缓冲区。
inet_pton(int af, const char *src, void *dst)
该函数将字符串src转换为af地址族中的网络地址结构,然后将该网络地址结构复制到dst。参数af必须是AF_INET或AF_INET6。DST是按网络字节顺序写的。
Inet_pton()成功时返回1(网络地址已成功转换)。0如果SRC不包含表示指定地址族中有效网络地址的字符串,则返回。如果af不包含有效的地址族,则返回-1并将errno设置为EAFNOSUPPORT。
与inet_aton(3)和inet_addr(3)不同,inet_pton()支持IPv6地址。另一方面,inet pton()只接受点分十进制表示法的IPv4地址,而inet_aton(3)和inet_addr(3)允许更通用的数字和点表示法(十六进制和八进制数字格式,以及不需要显式写入所有四个字节的格式)。对于同时处理IPv6 ad- 1地址和数字点表示法的IPv4地址的接口,请参见getaddrinfo(3).
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
这个函数将af地址族中的网络地址结构src转换为字符串。结果字符串被复制到dst所指向的缓冲区,dst必须是一个非空指针。调用方在参数size中指定此缓冲区中可用的字节数。
Inet_ntop()扩展了inet_ntoa(3)函数以支持多个地址族,inet_ntoa(3)现在被认为是不推荐的,而支持Inet_ntop()。目前支持的地址族如下:
如果成功,inet_ntop()返回一个指向dst的非空指针。如果有错误,则返回NULL,并设置errno来指示错误。
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
成员是一个sockaddr_in结构体,具体见上面介绍。
主要是构造函数,构造分为sockaddr_in构造和ip地址,端口号构造。网络地址结构的设置与获取,以及网络地址的打印。
其中主要用到的函数,inet_pton与inet_ntop,将字符串src转换为af地址族中的网络地址结构与将af地址族中的网络地址结构src转换为字符串。htons与ntohs,主机端口号变成网络端口号与网络端口号变成主机端口号。
//InetAddress.h
#pragma once
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include "copyable.h"
#include "Log.h"
class InetAddress : copyable {
public:
InetAddress(uint16_t port = 8000, const char* ip = "127.0.0.1");
InetAddress(sockaddr_in addr) {
addr_ = addr;
}
uint16_t toPort() const {
return ntohs(addr_.sin_port);
}
std::string toIp() const;
std::string toIpPort() const;
sa_family_t family() const {
return addr_.sin_family;
}
sockaddr_in* getSockAddr() { return &addr_; }
void setSockAddr(sockaddr_in addr) { addr_ = addr; }
void setSockAddr(uint16_t port, const char* ip);
private:
struct sockaddr_in addr_;
};
//InetAddress.cpp
#include "InetAddress.h"
std::string InetAddress::toIpPort() const {
return toIp() + " : " + std::to_string(toPort());
}
std::string InetAddress::toIp() const {
char buf[64] = {0};
if (::inet_ntop(addr_.sin_family, &addr_.sin_addr, buf, sizeof buf) == nullptr) {
LOG_ERROR("%s--%s--%d--%d : inet_ntop error\n", __FILE__, __FUNCTION__, __LINE__, errno);
}
return buf;
}
InetAddress::InetAddress(uint16_t port, const char* ip) {
bzero(&addr_, sizeof addr_);
addr_.sin_family = AF_INET;
if (::inet_pton(addr_.sin_family, ip, &addr_.sin_addr) != 1) {
LOG_FATAL("%s--%s--%d--%d : inet_pton error\n", __FILE__, __FUNCTION__, __LINE__, errno);
}
addr_.sin_port = htons(port);
}
void InetAddress::setSockAddr(uint16_t port, const char* ip) {
bzero(&addr_, sizeof addr_);
addr_.sin_family = AF_INET;
if (::inet_pton(addr_.sin_family, ip, &addr_.sin_addr) != 1) {
LOG_FATAL("%s--%s--%d--%d : inet_pton error\n", __FILE__, __FUNCTION__, __LINE__, errno);
}
addr_.sin_port = htons(port);
}