Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 8 октября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

ПРОГРАММИРОВАНИЕ НА C и С++



Программисты долго мучаются с кодом прогаммы, изучают С++, WinAPI функции, MSDN. Потом пишут банальную систему защиты или навешивают банальный протектор, а крэкеры и реверсеры справляются с такой защитой за 5 минут. В итоге, продажи программы почти нулевые. Чтобы такого не допустить, тут самому надо немного поднабрать опыта отладки, реверсинга, тот же отладчик Ollydbg изучить или дизассемблер IDA Pro. Но где искать по крохам эти знания? Нет, конечно можно годами "методом тыка" разбираться, но куда быстрее видеокурс специальный посмотреть. Вот тут он есть: ссылка. Автор курса с большим опытом и объясняет понятно, я из этого курса много узнал про то как работает компьютер, процессор, про инструменты специальные и как с ними работать. Мои коллеги программисты на работе ничего такого и не знают, теперь я им нос утру.
Те, кто работал с tcp-ip сокетами, знают про всякие подводные камни, связаные с этим.
Приведу несколько из них.

Первый: данные в tcp-ip стеке могут появляться не все сразу, а кусками. Если клиент послал
нам данные с помощью одной функции send(), это совсем не значит, что они могут быть приняты одной
функцией recv().
Второй: если с отправителем данных что либо случилось, и он не смог данные полностью, то возможны зависоны на функции recv() (при использовании блокирующих сокетов).Аналогично для фукнции send().


Вашему вниманию представлены функции SendNBytes() и RecvNBytes(), которые избавлены от данных недостатков: используется функция select() для установки величины таймаута на однократный прием данных, и используется тот факт, что функция recv() в случае удачного приема возвращает количество байт, которые были реально приняты.

Вот, собственно, функции:



#define     _SOCKET_TIMEOUT    5000000     //величина таймаута в микросекундах

int SendNBytes(int nSocket, char *pBuffer, int iMessageLength)
{
  int     iRC         = 0;
  int     iSendStatus = 0;
  timeval SendTimeout;

  //установка величины таймаута
  SendTimeout.tv_sec  = 0;
  SendTimeout.tv_usec = _SOCKET_TIMEOUT;              

  fd_set fds;
  FD_ZERO(&fds);
  FD_SET(nSocket, &fds);


  //..до тех пор, пока нам нужно посылать данные...
  while(iMessageLength > 0)
  {
    iRC = select(0, NULL, &fds, NULL, &SendTimeout);

    //истек таймаут, возврат ошибки
    if(!iRC)
      return -1;

    //произошла ошибка
    if(iRC < 0)
      return WSAGetLastError();

    //отправить несколько байт
    iSendStatus = send(nSocket, pBuffer, iMessageLength, 0);   
                                                         
    //произошла ошибка в момент отправки данных
    if(iSendStatus < 0)
      return WSAGetLastError();
    else
    {
      //обновить буфер и счетчик
      iMessageLength -= iSendStatus;
      pBuffer += iSendStatus;
    }
  }

  return 0;
}






//функция приема данных
int ReceiveNBytes(int nSocket, char *pBuffer, int iStillToReceive)
{
  int     iRC               = 0;
  int     iReceiveStatus    = 0;
  timeval ReceiveTimeout;

  //установка величины таймаута
  fd_set fds;
  FD_ZERO(&fds);
  FD_SET(nSocket, &fds);

  ReceiveTimeout.tv_sec  = 0;
  ReceiveTimeout.tv_usec = _SOCKET_TIMEOUT;             // 500 ms

  //..пока данные не посланы..
  while(iStillToReceive > 0)
  {
    iRC = select(0, &fds, NULL, NULL, &ReceiveTimeout);
    
    //выход по таймауту
    if(!iRC)
      return -1;

    //произошла какая то ошибка
    if(iRC < 0)
      return WSAGetLastError();

    //прием нескольких байт
    iReceiveStatus = recv(nSocket, pBuffer, iStillToReceive, 0);

    //произошла ошибка в момент функции recv()
    if(iReceiveStatus < 0)
    {
      return WSAGetLastError();
    }
    else
    {
      //изменили величину счетчика и буфер
      iStillToReceive -= iReceiveStatus;
      pBuffer += iReceiveStatus;
    }
  }

  return 0;
}




как пользоваться:

Хорошим тоном считается посылка в начале основного сообщения информацию о длине сообщения.
Нужно договориться (разработчикам клиента и сервера), что, например, первые 2 или 4 байта в начале
сообщения будут длиной сообщения. Поэтому, полное сообщение из сокета можно получить примерно так:



TCHAR   *szMessage;
TCHAR   szLength[4];
int nLength;

if(RecvNBytes(nSocket, szLength, 2) != 0)   //приняли первые 2 байта - длину
{
  return FALSE;
}

nLength = atoi(szLength);       //преобразовали 2 байта в длину
szMessage = new TCHAR[szLength];

if(RecvNBytes(nSocket, szMessage, nLength) !=0) //приняли полное сообщение
{
  return FALSE;
}




<< ВЕРНУТЬСЯ В ПОДРАЗДЕЛ

<< ВЕРНУТЬСЯ В ОГЛАВЛЕНИЕ




Материалы находятся на сайте https://exelab.ru/pro/



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS