Over the course of the years, I have pieced together a C++ OO socket library that I use (successfully) for TCP and UDP communications. When I bind() to a socket, and a hostname or IP address is given, I use gethostbyname().
Through a little research this morning, I discovered that the gethostbyname() function is considered "obsolete", and instead getaddrinfo() should be used. Is this correct?
The
example code I have seen that describes the usage of getaddrinfo() does not work well with the design of the socket library I developed, namely because an attempt is made to create a socket using information returned by getaddrinfo(). In my code, the socket has already been created before I ever attempt to bind() to a socket.
Below is a snippet of my code, which employs gethostbyname(). Can someone please provide some ideas as to how I should approach incorporating the getaddrinfo() into my code, or even if I should?
Should I defer opening/creating the socket until the server application calls bind()? Or in the case of a client application, until that application calls connect()?
I am not too keen on defering the opening of the socket from the Socket() constructor, and thus I wonder if the implementation I have is acceptable?
Anyhow, any comments are appreciated -- but please keep them in layman's terms!
Code:
////////////////////////////////////////////////////////////////////////////////
//
// Method: Socket (constructor)
//
////////////////////////////////////////////////////////////////////////////////
Socket::Socket(int domain, int type, int protocol) :
m_Domain(domain),
m_Type(type),
m_Protocol(protocol)
{
if ((m_Socket = socket(m_Domain, m_Type, m_Protocol)) < 0)
{
throw std::runtime_error("Could not create socket!");
}
}
...
////////////////////////////////////////////////////////////////////////////////
//
// Method: Bind
//
////////////////////////////////////////////////////////////////////////////////
void
Socket::Bind(const std::string& address, unsigned short port)
{
sockaddr_in addr;
FillAddress(address, port, addr);
if (bind(m_Socket, (sockaddr*) &addr, sizeof(sockaddr_in)) < 0)
{
throw std::runtime_error("Could not bind to socket!");
}
}
////////////////////////////////////////////////////////////////////////////////
//
// Method: FillAddress
//
////////////////////////////////////////////////////////////////////////////////
void
Socket::FillAddress(const std::string& address, unsigned short port, sockaddr_in& addr)
{
hostent* host = gethostbyname(address.c_str());
if (host == 0)
{
throw std::runtime_error("Could not get hostname from given address!");
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = m_Domain;
addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
addr.sin_port = htons(port);
}
I have a TCPServerSocket, a TCPSocket (for clients), and a UDPSocket that subclass from Socket. Here's how I would typically use the TCPServerSocket in an application:
Code:
...
const unsigned short port = 9100;
TCPServerSocket server;
server.Bind("192.168.6.128", port);
server.Listen();
server.EnableReuseAddress();
...