winsock пересылка и исполнение бинарного файла

 
0
 
C++
ava
Anbore | 24.11.2016, 04:30
Всем доброго времени суток.
Имеется сервер и клиент. Нужно с клиента переслать бинарный файл на сервер и исполнить его.
Файл открывается в бинарном режиме, читает в буфер, делает send. Сервер делает recv и из буфера записывает в файл, потом переименовывает.
Пытаюсь переслать и получаю ошибку: "Сделана попытка выполнить операцию на объекте, не являющемся сокетом." 

клиент

#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <locale.h>
#include <string>

#pragma comment(lib, "Ws2_32.lib")

#define PORT 6091

void getError(DWORD errCode)
   {
   char error[1000]; 
   FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
                 NULL,
                 WSAGetLastError(),
                 MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT),
                 error, sizeof(error), NULL); 
   printf("\nОшибка: %s\n", error); 
   getchar();
   }

int main(int argc, char *argv[])
{

    setlocale(LC_ALL, "Russian");

    WSADATA winsock;
    SOCKET sock;
    if ((WSAStartup(MAKEWORD(2, 0), &winsock))!=NO_ERROR)
    {
        DWORD error = WSAGetLastError();
        getError(error);
        return -1;
    }

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET)
    {
        DWORD error = WSAGetLastError();
        getError(error);
        return -2;
    }

    sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    addr.sin_port = htons(PORT);

    if (connect(sock, (sockaddr*)&addr, sizeof(addr)) != 0)
    {
        DWORD error = WSAGetLastError();
        getError(error);
        return -3;
    }

    printf("Подключение успешно !\n");
    printf("Посылаю файл .. \n");

    FILE *otpr_file;
    char buff[200];
    memset(buff, 0, 200);
    if ((otpr_file = fopen("D:\\Projects\\server_client\\Debug\\rufus.exe", "rb")) == NULL)
    {
        printf("Ошибка открытия файла.\n");
        return -4;
    }
    else
    {
        for (;;)
        {
            fread(buff, 5, 200, otpr_file);
            int send_chars = send(sock, buff, 200, 0);
            if (send_chars > 0)
            {
                printf("Получено байт: %d\n", send_chars);
            }
            else if (send_chars == 0)
            {
                printf("Соединение закрыто\n");
                break;
            }
            else if (send_chars == SOCKET_ERROR)
            {
                DWORD error = WSAGetLastError();
                getError(error);
                return -5;
                break;
            }
        }
        fclose(otpr_file);
        closesocket(sock);
        WSACleanup();
        return 0;
    }
}


сервер

#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <locale.h>
#include <string>

#pragma comment(lib, "Ws2_32.lib")

#define PORT 6091

void getError(DWORD errCode) 
   {
   char* error; 
   FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
      NULL,
      errCode != 0 ? errCode : WSAGetLastError(),
      MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT),
      error,
      sizeof(error),
      NULL);  
   printf("\nОшибка: %s\n", error); 
   getchar();
   }

int main()
   {
    setlocale(LC_ALL, "Russian");
    
   WSADATA winsock;
   if (FAILED(WSAStartup(MAKEWORD(1, 1), &winsock)))
   {
       DWORD error = WSAGetLastError();
       getError(error);
       return -1;
   }
   SOCKET sock, sub;
   sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (sock == INVALID_SOCKET)
   {
       DWORD error = WSAGetLastError();
       getError(error);
       return -2;
   }
   sockaddr_in addr;
   
   sockaddr_in incomingAddress;
   int addressLen = sizeof(incomingAddress);
   memset(&addr, 0, sizeof(addr));
   addr.sin_family = AF_INET;
   addr.sin_port = htons(PORT);
   addr.sin_addr.s_addr = inet_addr("127.0.0.1");
   if (bind(sock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) 
   {
       DWORD error = WSAGetLastError();
       getError(error);
       return -3;
   }

  if (listen(sock, SOMAXCONN) == SOCKET_ERROR) 
  {
      DWORD error = WSAGetLastError();
       getError(error);
       return -4;
   }
  char buffer[200];
  FILE * prin_file;
  std::string fname = "file" + std::to_string(rand() % 1000) + ".exe";
  char new_name[20];
  memset(new_name, 0, sizeof(fname));
  strncpy(new_name, fname.c_str(), sizeof(new_name) - 1);
  prin_file = fopen(new_name, "wb");
   printf("Ожидание подключения\n");
   for (;;)
   {
       sub = accept(sock, (sockaddr*)&incomingAddress, &addressLen);
       if (sub != INVALID_SOCKET)
       {
           printf("Клиент подключен!\n");
           for (;;) {
               int recv_chars = recv(sub, buffer, 200, 0);
               if (recv_chars > 0)
               {
                   printf("Получено байт: %d\n", recv_chars);
                   fwrite(buffer, 5, 200, prin_file);
               }
               else if (recv_chars == 0)
               {       
                printf("Соединение закрыто\n");
                
                break;
           }  else if (recv_chars == SOCKET_ERROR)
               {
                   DWORD error = WSAGetLastError();
                   getError(error);
                   return -5;
                   break;
               }
           }    
       }
   }
   fclose(prin_file);

   STARTUPINFO si;
   PROCESS_INFORMATION pi;
   memset(&si, 0, sizeof(si));
   memset(&pi, 0, sizeof(si));
   if(!CreateProcess((LPCSTR)prin_file, NULL, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi))
   {
       DWORD error = WSAGetLastError();
       getError(error);
       return -6;
   }
   closesocket(sub);
   closesocket(sock);
   WSACleanup();
   return 0;
}

Kommentare (5)
ava
feodorv | 24.11.2016, 21:14 #
У Вас в коде замечательно проверяются ошибки, но вот почему-то на fread проверки нет. Хуже того:
Цитата (Anbore @  24.11.2016,  04:30 findReferencedText)
    fread(buff, 5, 200, otpr_file);

Здесь написано: прочитать из otpr_file в buff 200 блоков по 5 байт (подозреваю, что это просто описка))). Итого запрос на 1000 байт, а буфер даёте на 200 байт. Происходит запись прочитанных из файла данных за пределами буфера. Программа при этом не падает, видимо, ничего жизненно важного для процесса не задето, но вот кислород перекрыт - перезаписывается значение переменной sock, которая теперь хранит не идентификатор сокета, а не известно что.
ava
vol4ek | 24.11.2016, 22:33 #
добавлю

FILE * prin_file;
if(!CreateProcess((LPCSTR)prin_file, NULL, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi))


stdio.h


typedef struct _iobuf
{
    char*    _ptr;
    int    _cnt;
    char*    _base;
    int    _flag;
    int    _file;
    int    _charbuf;
    int    _bufsiz;
    char*    _tmpfname;
} FILE;


Anbore, открыл недокументированный способ выдирания нужной строки из структуры силой мысли видимо. (LPCSTR)prin_file =) опа, и нет проблем. берите на заметку друзья, много кому понадобится.
ava
Aoizora | 08.12.2016, 18:30 #
Лол, прикольно. Тоже когда-то абузил размещение полей структур после прочтения книжки Эриксона, но такие вещи зависят от текущей имплементации библиотеки.
ava
_zorn_ | 08.12.2016, 21:48 #
О чувак, сокеты это такая забавная штука. Вот кажется все должно работать как ты думаешь, а хрен тебе. Ну например recv в лёгкую повесит все приложение если в сокете нет ничего.
send наверное тоже хз.
Короче select тебе в помощь :)

ЗЫ. Там реально неадекваты это все делали. Ну нечего читать - верни ты управление.
ЗЫЫ. Это про винду
ava
Aoizora | 08.12.2016, 23:28 #
Можно же просто в отдельном потоке запустить чтение и обработку.
Registrieren Sie sich oder melden Sie sich an, um schreiben zu können.
Unternehmen des Tages
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Mitwirkende
advanced
Absenden