IPv4地址的封装主要是对sockadr_in的封装, 这是别人写的一个跨平台的代码,觉得不错,故记录下来。如果您看到代码,觉得还有改进的地方,可以说出来分享一下。
头文件SocketAddress.h
namespace LinWin
{
#define NET_DEFAULT_IP "0.0.0.0"
class CSocketAddress
{
private:
sockaddr_in m_addr;
public:
CSocketAddress(const char *ip = NET_DEFAULT_IP, unsigned short port = 0);
CSocketAddress(const sockaddr_in &addr);
CSocketAddress(const CSocketAddress &addr);
CSocketAddress& operator=(const CSocketAddress &addr);
virtual ~CSocketAddress();
public:
inline const struct sockaddr_in* GetAddress() const
{ return &m_addr; }
//添加一个非const版本的GetAddress函数
inline struct sockaddr_in* GetAddress()
{ return &m_addr; }
inline void SetAddress(const struct sockaddr_in addr)
{ m_addr = addr; }
inline unsigned int AddressLength() const
{ return sizeof(struct sockaddr_in); }
inline int GetFamily() const
{ return m_addr.sin_family; }
inline void SetFamily(int fam)
{ m_addr.sin_family = fam; }
virtual unsigned int GetHost() const
{ return m_addr.sin_addr.s_addr; }
inline void SetHost(unsigned int addr)
{ m_addr.sin_addr.s_addr = addr; }
inline unsigned short GetPort() const
{ return m_addr.sin_port; }
inline void SetPort(unsigned short p)
{ m_addr.sin_port = p; }
virtual int Parse(const std::string& addrStr);
virtual int Parse(const std::string& addr, int port);
virtual std::string ToString() const;
};
}
实现文件SocketAddress.cpp
LinWin::CSocketAddress::CSocketAddress(const char *ip, unsigned short port)
{
memset(&m_addr, 0, sizeof(sockaddr_in));
m_addr.sin_family = AF_INET;
m_addr.sin_addr.s_addr = inet_addr(ip);
m_addr.sin_port = htons(port);
}
LinWin::CSocketAddress::CSocketAddress(const struct sockaddr_in& addr) : m_addr(addr)
{}
LinWin::CSocketAddress::CSocketAddress(const CSocketAddress& addr) : m_addr(addr.m_addr)
{}
LinWin::CSocketAddress::~CSocketAddress()
{}
LinWin::CSocketAddress& LinWin::CSocketAddress::operator=(const CSocketAddress& addr)
{
if (&addr != this)
{
m_addr = addr.m_addr;
}
return *this;
}
std::string LinWin::CSocketAddress::ToString() const
{
unsigned short port = ntohs(m_addr.sin_port);
std::string result = inet_ntoa(m_addr.sin_addr);
char buf[8];
sprintf(buf, ":%d", port);
result += buf;
return result;
}
int LinWin::CSocketAddress::Parse(const std::string& addrStr)
{
size_t i;
unsigned short port = 0;
size_t index = addrStr.find(":");
if (index == std::string::npos || (index + 1) == addrStr.length())
return -1;
const char* pData = addrStr.c_str();
i = 0;
while (isspace(pData[i]))
i++;
std::string tmp;
while (!isspace(pData[i]) && i < index)
{
tmp.push_back(pData[i]);
i++;
}
struct hostent *hostip = ::gethostbyname(tmp.c_str());
if (hostip == NULL)
return -1;
i = index + 1;
while (!isdigit(pData[i]) && i < addrStr.length())
i++;
port = atoi(pData + i);
memset(&m_addr, 0, sizeof(const struct sockaddr_in));
m_addr.sin_family = AF_INET;
memcpy((char*)&m_addr.sin_addr, hostip->h_addr, hostip->h_length);
m_addr.sin_port = htons(port);
return 0;
}
int LinWin::CSocketAddress::Parse(const std::string& addr, int port)
{
struct hostent *hostip = ::gethostbyname(addr.c_str());
if (hostip == NULL)
return -1;
memset(&m_addr, 0, sizeof(const struct sockaddr_in));
m_addr.sin_family = AF_INET;
memcpy((char*)&m_addr.sin_addr, hostip->h_addr, hostip->h_length);
m_addr.sin_port = htons(port);
return 0;
}
命名空间是我自己添加的,如果不需要可以去掉。整体的代码是比较简单的,就是类的基础知识和socketaddr_in结构体的使用。类中留有两个接口,一个是解析像这样”域名 + 端口号”(如”www.baidu.com:80”)形式的接口;一个是输出”IP + 端口”(如”192.168.0.1:80”)这样的形式的接口。想要修改这两个接口,可以直接继承,在子类中重写这个接口。
新增一个接口,是把“域名”和“端口号”作为两个参数传入。