_Great_
19.11.2006, 00:01
Написал недавно удобный класс Socket для работы с сокетами.
Класс содержит следующие методы:
Socket(bool create=1, int type=SOCK_STREAM, int protocol=IPPROTO_TCP)
Конструктор класса Socket. Флаг create указывает на необходимость создания сокета в конструкторе.
По умолчанию принимается тип SOCK_STREAM и протокол IPPROTO_TCP (TCP/IP)
Socket(SOCKET)
создание объекта на основе уже созданного сокета
Socket(Socket&)
конструктор копии
~Socket()
деструктор
int create(int type=SOCK_STREAM, int protocol=IPPROTO_TCP)
создает сокет указанного типа и протокола
int set_buffer_size(int size)
установка размера входного буфера. возвращает старое значение
int get_buffer_size()
получение размера входного буфера
bool set_terminate_flag(bool value)
установка флага, при котором будет записываться 0 в конец буфера при получении данных. возвращает старое значение
bool get_terminate_flag()
получение флага записи 0
int get_last_length()
получение длины последнего полученного блока данных
static char* getlasterror()
возвратить текстовое описание ошибки. утечки памяти не происходит, т.к. место зарезервировано в сегменте данных
int bind(int port, int addr=INADDR_ANY)
биндит сокет к порту и указанному адресу.
эта и все остальные сокетные функции возвращает -1 при ошибке и 0, если все нормально
int connect(char* host_name, int port)
соединяется с указанном хостом и портом. Можно передать доменное имя
int connect_to(sockaddr_in* sa)
соединяется согласно параметрам, указанным в заполненной структуре SOCKADDR_IN
int close()
закрывает сокет
int listen(int backlog=5)
переводит сокет в прослушивающий режим
Socket* accept(sockaddr_in* from=0)
ждет входящего соединения. Можно передать адрес sockaddr_in, куда будет записан адрес удаленного компьютера. Возвращает новый объект Socket, который нужно будет удалить оператором delete.
char* recv(char* buffer, int buflen=0)
получает данные из сокета. Если передать 0 вместо длины буфера, будет использоваться дефолтное значение
unsigned char* recv(unsigned char* buffer, int buflen=0)
перегруженный аналог предыдущей функции для типа unsigned char*
char* recv()
получение данных с автовыделением памяти. Она должна будет удалена вызовом delete.
int send(char* buffer, int buflen=0)
и int send(unsigned char* buffer, int buflen=0)
отправка данных в сокет. Если указать длину 0, то длина будет вычислена с помощью strlen() (до первого нулевого байта)
Резолвинг доменных имен:
static char* nslookup(char* host_name)
и static DWORD nslookup_raw(char* host_name)
возвращают IP-адрес, соответствующий домену, соответственно в строковом и числовом форматах.
Поддержка потокового ввода-вывода для строк
Socket& operator<<(char* string)
и Socket& operator>>(char* buffer)
Пример клиентской программы:
Socket sock;
sock.connect("mail.ru", 80);
sock<<"GET http://mail.ru/ HTTP/1.0\r\n\r\n";
char buf[1024];
sock.set_buffer_size(sizeof(buf));
sock>>buf;
MessageBox(0, buf, "mail.ru", 0);
sock.close();
Пример серверной программы (с проверкой на ошибки):
Socket serv;
if(serv.bind(8080)==-1)
return MessageBox(0, serv.getlasterror(), "Unable to bind socket", MB_ICONHAND);
if(serv.listen()==-1)
return MessageBox(0, serv.getlasterror(), "Unable to bind socket", MB_ICONHAND);
Socket *remote = serv.accept();
if(!remote)
return MessageBox(0, serv.getlasterror(), "Unable to accept connection", MB_ICONHAND);
char buf[1024];
remote->set_buffer_size(sizeof(buf));
(*remote)>>buf;
(*remote)<<"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>Socket class demo application</h1>Hello, World!";
remote->close();
serv.close();
delete remote;
MessageBox(0, buf, "Remote", 0);
Пример наследования - класс Socks для работы с SOCKS-прокси:
class Socks: public Socket
{
public:
int connect(char* proxy_host, int proxy_port, char* dest_host, int dest_port);
};
// Connect to SOCKS
int Socks::connect(char* proxy_host, int proxy_port, char* dest_host, int dest_port)
{
set_terminate_flag(0);
if(Socket::connect(proxy_host, proxy_port)==-1)
return -1;
unsigned char packet[1024];
int bytes=0;
memcpy(packet, "\x05\x01\x00", 3);
send(packet, 3);
recv(packet, sizeof(packet));
bytes = get_last_length();
if(*(WORD*)packet != 0x0005)
{
close();
return -1;
}
DWORD ip = nslookup_raw(dest_host);
if(!ip)
{
close();
return -1;
}
packet[0] = 5; // VERSION: 5
packet[1] = 1; // METHOD: CONNECT
packet[2] = 0; // RSV: 0
packet[3] = 1; // ADTYPE: IPv4
*(DWORD*)&(packet[4]) = ip;
*(WORD*)&(packet[8]) = htons(dest_port);
send(packet, 10);
recv(packet, sizeof(packet));
bytes = get_last_length();
if(bytes!=10 || packet[1])
{
close();
return -1;
}
set_terminate_flag(1);
return 0;
}
После вызова connect можно читать и писать в сокет как обычно
Скачать:
socket.h (2 Kb) (http://gr8.cih.ms/data/socket.h)
socket.cpp (6 Kb) (http://gr8.cih.ms/data/socket.cpp)
Класс содержит следующие методы:
Socket(bool create=1, int type=SOCK_STREAM, int protocol=IPPROTO_TCP)
Конструктор класса Socket. Флаг create указывает на необходимость создания сокета в конструкторе.
По умолчанию принимается тип SOCK_STREAM и протокол IPPROTO_TCP (TCP/IP)
Socket(SOCKET)
создание объекта на основе уже созданного сокета
Socket(Socket&)
конструктор копии
~Socket()
деструктор
int create(int type=SOCK_STREAM, int protocol=IPPROTO_TCP)
создает сокет указанного типа и протокола
int set_buffer_size(int size)
установка размера входного буфера. возвращает старое значение
int get_buffer_size()
получение размера входного буфера
bool set_terminate_flag(bool value)
установка флага, при котором будет записываться 0 в конец буфера при получении данных. возвращает старое значение
bool get_terminate_flag()
получение флага записи 0
int get_last_length()
получение длины последнего полученного блока данных
static char* getlasterror()
возвратить текстовое описание ошибки. утечки памяти не происходит, т.к. место зарезервировано в сегменте данных
int bind(int port, int addr=INADDR_ANY)
биндит сокет к порту и указанному адресу.
эта и все остальные сокетные функции возвращает -1 при ошибке и 0, если все нормально
int connect(char* host_name, int port)
соединяется с указанном хостом и портом. Можно передать доменное имя
int connect_to(sockaddr_in* sa)
соединяется согласно параметрам, указанным в заполненной структуре SOCKADDR_IN
int close()
закрывает сокет
int listen(int backlog=5)
переводит сокет в прослушивающий режим
Socket* accept(sockaddr_in* from=0)
ждет входящего соединения. Можно передать адрес sockaddr_in, куда будет записан адрес удаленного компьютера. Возвращает новый объект Socket, который нужно будет удалить оператором delete.
char* recv(char* buffer, int buflen=0)
получает данные из сокета. Если передать 0 вместо длины буфера, будет использоваться дефолтное значение
unsigned char* recv(unsigned char* buffer, int buflen=0)
перегруженный аналог предыдущей функции для типа unsigned char*
char* recv()
получение данных с автовыделением памяти. Она должна будет удалена вызовом delete.
int send(char* buffer, int buflen=0)
и int send(unsigned char* buffer, int buflen=0)
отправка данных в сокет. Если указать длину 0, то длина будет вычислена с помощью strlen() (до первого нулевого байта)
Резолвинг доменных имен:
static char* nslookup(char* host_name)
и static DWORD nslookup_raw(char* host_name)
возвращают IP-адрес, соответствующий домену, соответственно в строковом и числовом форматах.
Поддержка потокового ввода-вывода для строк
Socket& operator<<(char* string)
и Socket& operator>>(char* buffer)
Пример клиентской программы:
Socket sock;
sock.connect("mail.ru", 80);
sock<<"GET http://mail.ru/ HTTP/1.0\r\n\r\n";
char buf[1024];
sock.set_buffer_size(sizeof(buf));
sock>>buf;
MessageBox(0, buf, "mail.ru", 0);
sock.close();
Пример серверной программы (с проверкой на ошибки):
Socket serv;
if(serv.bind(8080)==-1)
return MessageBox(0, serv.getlasterror(), "Unable to bind socket", MB_ICONHAND);
if(serv.listen()==-1)
return MessageBox(0, serv.getlasterror(), "Unable to bind socket", MB_ICONHAND);
Socket *remote = serv.accept();
if(!remote)
return MessageBox(0, serv.getlasterror(), "Unable to accept connection", MB_ICONHAND);
char buf[1024];
remote->set_buffer_size(sizeof(buf));
(*remote)>>buf;
(*remote)<<"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>Socket class demo application</h1>Hello, World!";
remote->close();
serv.close();
delete remote;
MessageBox(0, buf, "Remote", 0);
Пример наследования - класс Socks для работы с SOCKS-прокси:
class Socks: public Socket
{
public:
int connect(char* proxy_host, int proxy_port, char* dest_host, int dest_port);
};
// Connect to SOCKS
int Socks::connect(char* proxy_host, int proxy_port, char* dest_host, int dest_port)
{
set_terminate_flag(0);
if(Socket::connect(proxy_host, proxy_port)==-1)
return -1;
unsigned char packet[1024];
int bytes=0;
memcpy(packet, "\x05\x01\x00", 3);
send(packet, 3);
recv(packet, sizeof(packet));
bytes = get_last_length();
if(*(WORD*)packet != 0x0005)
{
close();
return -1;
}
DWORD ip = nslookup_raw(dest_host);
if(!ip)
{
close();
return -1;
}
packet[0] = 5; // VERSION: 5
packet[1] = 1; // METHOD: CONNECT
packet[2] = 0; // RSV: 0
packet[3] = 1; // ADTYPE: IPv4
*(DWORD*)&(packet[4]) = ip;
*(WORD*)&(packet[8]) = htons(dest_port);
send(packet, 10);
recv(packet, sizeof(packet));
bytes = get_last_length();
if(bytes!=10 || packet[1])
{
close();
return -1;
}
set_terminate_flag(1);
return 0;
}
После вызова connect можно читать и писать в сокет как обычно
Скачать:
socket.h (2 Kb) (http://gr8.cih.ms/data/socket.h)
socket.cpp (6 Kb) (http://gr8.cih.ms/data/socket.cpp)