Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > C/C++ Сетевое программирование
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 15.08.2011, 11:12   #1
teapot
Пользователь
 
Регистрация: 04.12.2010
Сообщений: 23
По умолчанию Клиент-сервер(асинхронный) - передача файлов

Добрый день!
Пишу клиент и сервер с передачей текстового файла от клиента серверу. Задачу нужно решить с использованием неблокирующих сокетов. Всё в принципе работает, но файл почему-то передаётся не всегда, кроме того, если запускаю отдельно экзешники (т.е. не из билдера), то файл не передаётся вообще. Вот код клиента и сервера, и ещё приложен архив с проектом. Буду очень благодарна за помощь!

Клиент передаёт файл:
Код:
//---------------------------------------------------------------------------

   FILE *F;
   if (!(F=fopen("1.txt","r")))
   {
      perror("Open File");
      system("pause");
      exit(4);
   };
 
   char s[80];
   char p[80];
 
   while(!feof(F))
   {
      fgets(s,80,F);
      send(sock, s,sizeof(s),0);
      recv(sock,p,sizeof(s),0);
      printf("%s",p);
   };
   printf("\nThe file transfer completed.\n");
   fclose(F);
Сервер:

Код:
//---------------------------------------------------------------------------
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#include <algorithm>
#include <set>
using namespace std;
#include <time.h>
 
#include <conio.h>
#include <vcl.h>
#pragma hdrstop
 
//---------------------------------------------------------------------------
 
#pragma argsused
//---------------------------------------------------------------------------
int Number;
WSADATA ws;//информация о сокете
int main(int argc, char* argv[])
{
 
    // Шаг 1 - инициализация библиотеки Winsock
    if (FAILED (WSAStartup (MAKEWORD( 1,1 ), &ws)))
    {
       perror("WSAStartup");
       system("pause");
       exit(1);
    }
 
    // Шаг 2 - создание сокета
    SOCKET sock, listener;
 
    struct sockaddr_in addr;
    char buf[1024];
    int bytes_read;
 
    listener = socket(AF_INET, SOCK_STREAM, 0);
    if(listener < 0)
    {
        perror("socket");
        system("pause");
        exit(2);
    }
    ULONG ulBlock;
    ulBlock = 1;
    //аналог fcntl
    if (ioctlsocket(listener, FIONBIO, &ulBlock) == SOCKET_ERROR)
    {
        perror("ioctlsocket_listener");
        system("pause");
        exit(3);
    }
 
    // Шаг 3 - установка соединения
    addr.sin_family = AF_INET;
    addr.sin_port = htons(666);
    addr.sin_addr.s_addr = INADDR_ANY;
    if(bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        system("pause");
        exit(4);
    }
 
    listen(listener, 1);
 
    Number = 0;
 
    FD_SET ReadSet;
    int ReadySock;
 
    set<int> clients;
    clients.clear();
 
    // цикл извлечения запросов на подключение из
    // очереди
    while(1)
    {
       // Заполняем множество сокетов
       FD_ZERO(&ReadSet);
       FD_SET(listener, &ReadSet);
 
       for(set<int>::iterator it = clients.begin(); it != clients.end(); it++)
            FD_SET(*it, &ReadSet);
 
       // Задаём таймаут
       timeval timeout;
       timeout.tv_sec = 15;
       timeout.tv_usec = 0;
 
       // Ждём события в одном из сокетов
       int mx = max(listener, *max_element(clients.begin(), clients.end()));
 
       if ((ReadySock = select(mx+1, &ReadSet, NULL, NULL, &timeout)) ==
                SOCKET_ERROR)
       {
          perror("Select");
          system("pause");
          exit(6);
       }
 
       if (FD_ISSET(listener, &ReadSet))
       {
          sock = accept(listener, NULL, NULL);
          if (sock == INVALID_SOCKET)
          {
             perror("accept");
                break;
          }
 
          if (ioctlsocket(sock, FIONBIO, &ulBlock) == SOCKET_ERROR)
          {
              perror("ioctlsocket_sock");
              break;
          }
 
          //добавили в список
          clients.insert(sock);
       }
 
       for(set<int>::iterator it = clients.begin(); it != clients.end(); it++)
       {
          if(FD_ISSET(*it, &ReadSet))
          {
             Number++;   // увеличиваем счетчик
             AnsiString filename;
             filename = "Res"+IntToStr(Number)+".txt";
 
             FILE *F;
             if (!(F = fopen(filename.c_str(),"w")))
             {
                 perror("Create File");
                 break;
             };
 
             while( (bytes_read = recv(*it, buf, 1024, 0))>0 )
             {
                fprintf(F,buf);
                printf(buf);
                // Отправляем данные обратно клиенту
                send(*it, buf, bytes_read, 0);
             }
 
             fprintf(F,"\0");
             fclose(F);
             delete(F);
             F = NULL;
             closesocket(*it);
             clients.erase(*it);
          } 
          printf("\nReceiving the file %d is complete.\n",Number);
       } 
    }
 
     closesocket(sock);
     closesocket(listener);
    _exit(0);
 
    return 0;
}
Вложения
Тип файла: rar AClientServer.rar (674.3 Кб, 90 просмотров)
teapot вне форума Ответить с цитированием
Старый 16.08.2011, 22:56   #2
teapot
Пользователь
 
Регистрация: 04.12.2010
Сообщений: 23
Хорошо

Проблема решена.
Видимо, так как сокеты асинхронные, сервер открывает для клиента сокет и принимает данные до тех пор, пока не выполнится какое-то условие. То есть на каждом шаге бесконечного цикла могут поступить данные от любого из клиентов. Поэтому внутренний цикл, во время которого у меня сервер должен был обслуживать конкретного клиента (после чего закрывать сокет), не нужен - вместо него на каждом шаге внешнего цикла принимаются порция данных уже "открытого" клиента.

Вот работающий код сервера.

Код:
//---------------------------------------------------------------------------
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#include <algorithm>
#include <map>
using namespace std;
#include <time.h>

#include <conio.h>
#include <vcl.h>
#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
//---------------------------------------------------------------------------
int Number;
WSADATA ws;
int main(int argc, char* argv[])
{

    if (FAILED (WSAStartup (MAKEWORD( 1,1 ), &ws)))
    {
       perror("WSAStartup");
       system("pause");
       exit(1);
    }

    SOCKET sock, listener;
    struct sockaddr_in addr;
    char buf[1024];
    int bytes_read;

    listener = socket(AF_INET, SOCK_STREAM, 0);
    if(listener < 0)
    {
        perror("socket");
        system("pause");
        exit(2);
    }
    ULONG ulBlock;
    ulBlock = 1;
    if (ioctlsocket(listener, FIONBIO, &ulBlock) == SOCKET_ERROR)
    {
        perror("ioctlsocket_listener");
        system("pause");
        exit(3);
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons(666);
    addr.sin_addr.s_addr = INADDR_ANY;
    if(bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        system("pause");
        exit(4);
    }

    listen(listener, 1);

    Number = 0;

    FD_SET ReadSet;
    int ReadySock;

    map <int,AnsiString> clients;
    clients.clear();

    typedef map<int,AnsiString>::value_type valType;

    // цикл извлечения запросов на подключение из
    // очереди
    while(1)
    {
       // Заполняем множество сокетов
       FD_ZERO(&ReadSet);
       FD_SET(listener, &ReadSet);

       for(map<int,AnsiString>::iterator it = clients.begin(); it != clients.end(); it++)
            FD_SET((*it).first , &ReadSet);

       timeval timeout;
       timeout.tv_sec = 15;
       timeout.tv_usec = 0;

       int mx = listener;
       for(map<int,AnsiString>::iterator it = clients.begin(); it != clients.end(); it++)
       {
          if ((*it).first > listener)
             mx = (*it).first;
       };

       // Ждём события в одном из сокетов

       if ((ReadySock = select(mx+1, &ReadSet, NULL, NULL, &timeout)) ==
		SOCKET_ERROR)
       {
          perror("Select");
          system("pause");
          exit(6);
       }

       if (FD_ISSET(listener, &ReadSet))
       {
          sock = accept(listener, NULL, NULL);
	  if (sock == INVALID_SOCKET)
	  {
	     perror("accept");
             break;
          }

          if (ioctlsocket(sock, FIONBIO, &ulBlock) == SOCKET_ERROR)
          {
              perror("ioctlsocket_sock");
              break;
          }


          Number++;   // увеличиваем счетчик
                   // подключившихся клиентов
          clients.insert( valType(sock,"Res"+IntToStr(Number)+".txt"));()  (sock,"Res"+IntToStr(Number)+".txt");

          AnsiString filename;
          filename = "Res"+IntToStr(Number)+".txt";

          FILE *F;
          if (!(F = fopen(filename.c_str(),"w")))
          {
              perror("Create File");
              break;
          };
          fclose(F);
       }

       for(map<int,AnsiString>::iterator it = clients.begin(); it != clients.end(); it++)

       {
          if(FD_ISSET((*it).first, &ReadSet))
          {
             FILE *F;
             if (!(F = fopen((*it).second.c_str() ,"a")))
             {
                 perror("Create File");
                 break;
             };

             bytes_read = recv((*it).first, buf, 1024, 0);
             if(bytes_read <= 0)
             {
                 // Соединение разорвано, удаляем сокет из множества
                 closesocket((*it).first);
                 clients.erase((*it).first);
                 continue;
             }
             //записали данные в файл
             fwrite(buf, sizeof(char), strlen(buf), F);
             // Отправляем данные обратно клиенту
             send((*it).first, buf, bytes_read, 0);

             fclose(F);
             delete(F);
             F = NULL;
          }
          printf("\nReceiving the part of file %d is complete.\n",Number);
       }      
    }
    closesocket(sock);
    closesocket(listener);
    return 0;
}
teapot вне форума Ответить с цитированием
Старый 19.08.2011, 19:20   #3
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

за использование функций как процедур следует кастрировать на месте, без суда и следствия.
mss вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Передача файла клиент-сервер Loveb C/C++ Сетевое программирование 2 27.05.2011 10:10
Need Help! Передача файлов (Сервер-Клиент) Elandar Работа с сетью в Delphi 1 25.07.2008 00:22
Передача файлов по интернету. Клиент-сервер. Kukkk Работа с сетью в Delphi 4 03.12.2007 06:08
Передача файлов на WEB-сервер SeregaP Работа с сетью в Delphi 18 09.04.2007 08:41