Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > winsock пересылка и исполнение бинарного файла


Автор: 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;
}


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

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

Добавлено через 3 минуты и 2 секунды
Цитата(Anbore @  24.11.2016,  04:30 Найти цитируемый пост)
                   fwrite(buffer, 5, 200, prin_file);

Тут тоже 5. Значит - не описка?

Автор: 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 =) опа, и нет проблем. берите на заметку друзья, много кому понадобится.

Автор: Aoizora 8.12.2016, 18:30
Лол, прикольно. Тоже когда-то абузил размещение полей структур после прочтения книжки Эриксона, но такие вещи зависят от текущей имплементации библиотеки.

Автор: _zorn_ 8.12.2016, 21:48
О чувак, сокеты это такая забавная штука. Вот кажется все должно работать как ты думаешь, а хрен тебе. Ну например recv в лёгкую повесит все приложение если в сокете нет ничего.
send наверное тоже хз. 
Короче select тебе в помощь smile

ЗЫ. Там реально неадекваты это все делали. Ну нечего читать - верни ты управление.
ЗЫЫ. Это про винду

Автор: Aoizora 8.12.2016, 23:28
Можно же просто в отдельном потоке запустить чтение и обработку.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)