Filer jeg kunne forestille mig den kunne være gal i:
IPAddress.h#ifndef IPADDRESS_H_INCLUDED
#define IPADDRESS_H_INCLUDED
#include <string>
#include <vector>
#include "Types.h"
#if defined(_WIN32)
#include <winsock2.h>
#elif defined(__linux__)
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
using namespace std;
class IPAddress
{
public:
//Opretter IPAddress ud fra entent ip, eller host navn
IPAddress(string & adr);
//Opretter IPAdress ud fra en in_addr struct
IPAddress(struct in_addr adr);
// Hvor mange addresser der er tilnyttet
UInt32 numAddresses();
//Returnere addressen med det givne index i in_addr
struct in_addr getAddress(UInt32 index);
//Rteurnere addressen med det givne index som streng
string getAddressString(UInt32 index);
//Hvor mange aliaser der er tilknyttet
UInt32 numAliases();
//Returnere aliaset med det givne index
string getAlias(UInt32 index);
//Returnere der officile navn
string getOfficialName();
operator string();
private:
//Laver opslaget fra in_addr
void fromInAddr(struct in_addr adr);
typedef vector<string> StringVector;
typedef vector<struct in_addr> InAddrVector;
StringVector m_aliases;
InAddrVector m_addresses;
string m_officialName;
};
#endif // IPADDRESS_H_INCLUDED
IPAddress.cpp#include "IPAddress.h"
#include "NetException.h"
#include "UnknownHostException.h"
#if defined(__linux__)
extern int h_errno;
#elif defined(_WIN32)
#include <windows.h>
#endif
IPAddress::IPAddress(string & adr)
{
struct in_addr adrIn;
struct hostent * entity;
#if defined(__linux__)
int error = inet_aton(adr.c_str(), &adrIn);
if(error == 0)
#elif defined(_WIN32)
adrIn.S_un.S_addr = inet_addr(adr.c_str());
if(adrIn.S_un.S_addr == INADDR_NONE && adr != "255.255.255.255")
#endif
{
entity = gethostbyname(adr.c_str());
if(entity == NULL)
{
#if defined(__linux__)
switch(h_errno)
{
case HOST_NOT_FOUND:
throw UnknownHostException(hstrerror(h_errno));
break;
default:
throw NetException(hstrerror(h_errno));
break;
}
#elif defined(_WIN32)
LPVOID lpMsgBuf;
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR) &lpMsgBuf,
0,
NULL);
string description = (char*) lpMsgBuf;
LocalFree(lpMsgBuf);
switch(err)
{
case WSAHOST_NOT_FOUND:
throw UnknownHostException(description);
break;
default:
throw NetException(description);
break;
}
#endif
}
else
{
int i = 0;
m_officialName = string(entity->h_name);
while(entity->h_aliases[i])
{
string alias = entity->h_aliases[i];
m_aliases.push_back(alias);
i++;
}
i = 0;
while(entity->h_addr_list[i])
{
struct in_addr inAdr = *((struct in_addr*) entity->h_addr_list[i]);
m_addresses.push_back(inAdr);
i++;
}
}
}
else
fromInAddr(adrIn);
}
IPAddress::IPAddress(struct in_addr adr)
{
fromInAddr(adr);
}
UInt32 IPAddress::numAddresses()
{
return m_addresses.size();
}
struct in_addr IPAddress::getAddress(UInt32 index)
{
return m_addresses[index];
}
string IPAddress::getAddressString(UInt32 index)
{
return string(inet_ntoa(m_addresses[index]));
}
UInt32 IPAddress::numAliases()
{
return m_aliases.size();
}
string IPAddress::getAlias(UInt32 index)
{
return m_aliases[index];
}
string IPAddress::getOfficialName()
{
return m_officialName;
}
IPAddress::operator string()
{
return m_officialName;
}
void IPAddress::fromInAddr(struct in_addr adr)
{
struct hostent * entity;
entity = gethostbyaddr((char*)&adr, sizeof(adr), AF_INET);
if(entity != NULL)
{
int i = 0;
m_officialName = string(entity->h_name);
while(entity->h_aliases[i])
{
string alias = entity->h_aliases[i];
m_aliases.push_back(alias);
i++;
}
i = 0;
while(entity->h_addr_list[i])
{
struct in_addr inAdr = *((struct in_addr*) entity->h_addr_list[i]);
m_addresses.push_back(inAdr);
i++;
}
}
else
{
m_addresses.push_back(adr);
m_officialName = getAddressString(0);
}
}
TCPSocket.h#ifndef TCPSOCKET_H_INCLUDED
#define TCPSOCKET_H_INCLUDED
#include "IPAddress.h"
class TCPSocket
{
friend class TCPServerSocket;
public:
TCPSocket(IPAddress & adr, UInt16 port, UInt32 timeOut = 0);
TCPSocket(string & adr, UInt16 port, UInt32 timeOut = 0);
~TCPSocket();
void setTimeOut(UInt32 timeOut);
void connect();
SInt32 read(void * buffer, SInt32 size);
SInt32 write(const void * buffer, SInt32 size);
void close();
IPAddress * getAddress();
UInt16 getPort();
UInt32 getTimeOut();
private:
TCPSocket(int socket, struct sockaddr_in sock_addr, UInt32 timeOut = 0);
void waitForData();
IPAddress m_address;
UInt16 m_port;
UInt32 m_timeOut;
int m_socket;
};
#endif // TCPSOCKET_H_INCLUDED
TCPSocket.cpp//TCPSocket.cpp
#include "TCPSocket.h"
#include "NetException.h"
#include "ConnectionLostException.h"
#include "TimerException.h"
#if defined(__linux__)
#include <unistd.h>
#endif
TCPSocket::TCPSocket(int socket, struct sockaddr_in sock_addr, UInt32 timeOut)
: m_address(sock_addr.sin_addr), m_port(ntohs(sock_addr.sin_port)), m_socket(socket), m_timeOut(timeOut)
{
}
TCPSocket::TCPSocket(IPAddress & adr, UInt16 port, UInt32 timeOut)
: m_address(adr), m_port(port), m_socket(0), m_timeOut(timeOut)
{
}
TCPSocket::TCPSocket(string & adr, UInt16 port, UInt32 timeOut)
: m_address(adr), m_port(port), m_socket(0), m_timeOut(timeOut)
{
}
TCPSocket::~TCPSocket()
{
//Hvis m_socket ikke er 0, er vi stadig forbundet
if(m_socket != 0)
{
close();
}
}
void TCPSocket::setTimeOut(UInt32 timeOut)
{
m_timeOut = timeOut;
}
void TCPSocket::connect()
{
//Denne struktur bruger vi til at forbinde mod
struct sockaddr_in adr_srvr;
//Denne tæller bruges til looping
UInt32 i;
//Denne variabel bruges til at tjekke for fejl
int error;
//Hvis m_socket ikke er 0 er vi allerede forbundet
if(m_socket != 0)
{
throw NetException("Already connected.");
}
//Opret en socket
m_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
#if defined(__linux__)
if(m_socket == -1)
{
throw NetException(strerror(h_errno));
}
#elif defined(_WIN32)
if(m_socket == INVALID_SOCKET)
{
LPVOID lpMsgBuf;
int err = WSAGetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL
);
string description((char*)lpMsgBuf);
LocalFree( lpMsgBuf );
throw NetException(description);
}
#endif
//Nulstil adressen
memset(&adr_srvr,0,sizeof(adr_srvr));
//Sæt adresse familie
adr_srvr.sin_family = AF_INET;
//Sæt port
adr_srvr.sin_port = htons(m_port);
//Vi bliver ved med at prøve at forbinde til alle adresser
//eller til det lykkes
error = -1;
i = 0;
while(error == -1 && i < m_address.numAddresses())
{
//Prøv med adresse nummer 'i'
adr_srvr.sin_addr = m_address.getAddress(i);
//Prøv at forbinde
error = ::connect(m_socket, (sockaddr*)&adr_srvr, sizeof(adr_srvr));
//Tæl 'i' op så vi næste gang tager næste adresse
i++;
}
//Hvis 'error' er -1 kunne vi ikke forbinde til nogen adresse
if(error == -1)
{
//Frigiv først vores socket
close();
//Kast derefter en exception
#if defined(__linux__)
throw NetException(strerror(h_errno));
#elif defined(_WIN32)
LPVOID lpMsgBuf;
int err = WSAGetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL
);
string description((char*)lpMsgBuf);
LocalFree( lpMsgBuf );
throw NetException(description);
#endif
}
}
SInt32 TCPSocket::read(void * buffer, SInt32 size)
{
//Denne variabel indeholder antallet af bytes
//som vi læser
SInt32 bytesRead;
//Vent først på data
waitForData();
//Hvis vi nåede til denne linje er der data til os
bytesRead = recv(m_socket,(char*)buffer,size,0);
//Hvis 'bytesRead' er -1, gik noget galt
if(bytesRead == -1)
{
#if defined(__linux__)
throw NetException(strerror(h_errno));
#elif defined(_WIN32)
LPVOID lpMsgBuf;
int err = WSAGetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL
);
string description((char*)lpMsgBuf);
LocalFree( lpMsgBuf );
throw NetException(description);
#endif
}
//Hvis vi læste 0 bytes er forbindelsen stoppet
else if(bytesRead == 0)
{
throw ConnectionLostException("Connection reset by peer.");
}
return bytesRead;
}
SInt32 TCPSocket::write(const void * buffer, SInt32 size)
{
SInt32 bytesWritten = send(m_socket,(char*)buffer,size,0);
//Hvis 'bytesWritten' er -1 gik noget galt
if(bytesWritten == -1)
{
#if defined(__linux__)
throw NetException(strerror(h_errno));
#elif defined(_WIN32)
LPVOID lpMsgBuf;
int err = WSAGetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL
);
string description((char*)lpMsgBuf);
LocalFree( lpMsgBuf );
throw NetException(description);
#endif
}
return bytesWritten;
}
void TCPSocket::close()
{
//Frigiv kun hvis vi har en socket
if(m_socket != 0)
{
#if defined(__linux__)
::close(m_socket);
#elif defined(_WIN32)
closesocket(m_socket);
#endif
m_socket = 0;
}
}
void TCPSocket::waitForData()
{
fd_set set;
struct timeval timeout;
int err;
FD_ZERO(&set);
FD_SET(m_socket,&set);
//Hvis m_timeOut er større end 0
if(m_timeOut > 0)
{
//Specificér hvor lang tid vi skal vente
timeout.tv_sec = (unsigned int)(m_timeOut / 1000);
timeout.tv_usec = (unsigned int)(m_timeOut % 1000) * 1000;
err = select(FD_SETSIZE,&set,NULL,NULL,&timeout);
}
else
{
//Vent til der er data eller til forbindelsen bliver lukket
err = select(FD_SETSIZE,&set,NULL,NULL,NULL);
}
//Hvis 'err' er 0 er tiden gået
if(err == 0)
{
throw TimerException("Timer timed out");
}
//Eller hvis 'err' er -1, er der gået noget galt
else if(err == -1)
{
#if defined(__linux__)
throw NetException(strerror(h_errno));
#elif defined(_WIN32)
LPVOID lpMsgBuf;
int err = WSAGetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL
);
string description((char*)lpMsgBuf);
LocalFree( lpMsgBuf );
throw NetException(description);
#endif
}
}
IPAddress * TCPSocket::getAddress()
{
return &m_address;
}
UInt16 TCPSocket::getPort()
{
return m_port;
}
UInt32 TCPSocket::getTimeOut()
{
return m_timeOut;
}
Og en copy pastet main.cpp//main.cpp
#include "Net.h"
#include "UnknownHostException.h"
#include "NetException.h"
#include "ConnectionLostException.h"
#include "TCPSocket.h"
#include <iostream>
#if defined(__linux__)
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
using namespace std;
void connectAndRead(string host)
{
//Denne buffer kommer til at indeholde, hvad vi læser
char buffer[1024];
//Denne variabel fortæller os, hvor mange bytes vi læser
int bytesRead;
//Lav et socket objekt uden timeout
TCPSocket sock(host,80);
//Forbind
sock.connect();
//HTTP request
string toSay = string("GET / HTTP/1.1\\r\\nHost: ") + host + string("\\r\\nConnection: close\\r\\n\\r\\n");
sock.write(toSay.c_str(),toSay.size());
try
{
//Denne løkke forlades, når forbindelsen lukkes
while(1)
{
//Læs til buffer
bytesRead = sock.read(buffer,sizeof(buffer));
//Skriv til standard out
cout.write(buffer,bytesRead);
cout.flush();
}
} catch (ConnectionLostException & cle)
{
//Serveren stoppede forbindelsen. Dette lader os bare forlade den
//ellers uendelige løkke
cout << cle << endl;
}
sock.close();
}
int main(int argc, char ** argv)
{
//Tjek om der er parametre
if(argc == 1)
{
cout << "Brug: " << argv[0] << " <IP|host>" << endl;
}
else
{
//netInit kan kaste exceptions
try
{
//Initialisér net komponenten
netInit();
try
{
string adrstr(argv[1]);
//Læs en hjemmeside
connectAndRead(adrstr);
} catch (NetException & nex)
{
cout << nex << endl;
}
//Frigiv net komponenten
netRelease();
} catch (NetException ex)
{
cerr << "Kunne ikke initialisere net komponenten: " << ex << endl;
}
}
return 0;
}