Программа сервера зависла при отправке - PullRequest
0 голосов
/ 12 февраля 2012

Я строю модель клиент-сервер на C. Клиенты подключаются к серверу, и они начинают обмениваться данными.Тем не менее, пользователь может завершить клиент в любое время в программе, но сервер не уведомлен об этом.Сервер продолжает отправлять эти данные даже после закрытия клиента.У меня сложилось впечатление, что функция send вернет -1, если серверу не удастся отправить данные, но моя серверная программа просто застряла на send

if((byteSent = send(new_fd, fileContents,  strlen(fileContents), 0)) == -1){ //

, программа просто останавливается в строке выше.*

Как мне преодолеть эту проблему?

// Код

   exitT = 0;
    //execution_count = 1;
    for(i=0;i<execution_count;i++)
    {  
        sleep(time_delay);

        //getting the current time on the server machine
        time_t t;
        time(&t);

        char *time=ctime(&t);
        printf("The Execution time at server =  %s\n",time);

        system(exec_command);

       /*Open the file, get file size, read the contents and close the file*/

        // Open the file
        fp = fopen(fileName,"r");

        // Get File Size
        fseek(fp,0,SEEK_END);
        dataLength = ftell(fp);
        rewind(fp);                

        fileContents = (char*)malloc(dataLength+1);
       // Read File
       fread(fileContents,1,dataLength,fp);
       fileContents[dataLength] = '\0';

        // Close file
         fclose(fp);    

       printf("sockfd = %d \n",new_fd);
       // send file length to client
       rc=send(new_fd, &dataLength,  sizeof(dataLength), 0) ;

       printf("length of client data = %d \n",rc);

        printf("sockfd = %d \n",new_fd);
       // send time to client
       rc=send(new_fd, time,  strlen(time), 0) ;

       printf("length of client time = %d \n",rc);

       usleep(20000);

       // Send file contents to Client
       while(dataLength>0){
            printf("sockfd = %d \n",new_fd);
            if((byteSent = send(new_fd, fileContents,  strlen(fileContents), 0)) == -1){
                printf("bytes sent = %d \n",byteSent);
                exitT = 1;
                break;
            }
            dataLength-=byteSent;
       }

       //Delete the log file 
       sprintf(deleteCommand,"rm %s",fileName);
       system(deleteCommand);
       if(exitT == 1)
           break;
     }

      bzero(fileName,sizeof(fileName));
      bzero(exec_command,sizeof(exec_command));
      bzero(deleteCommand,sizeof(deleteCommand));

      //decClientNum();
      kill(parent_id,SIGALRM);
      close(new_fd);  // parent doesn't need this
      printf("STATUS = CLOSED\n");

      exit(0);
  }   

Спасибо

Ответы [ 4 ]

1 голос
/ 12 февраля 2012

Я предполагаю, что вы кодируете систему Linux или Posix.

Если системный вызов, такой как send , не удается, он возвращает -1, а устанавливает errno;вы, вероятно, должны использовать errno , чтобы выяснить, почему это не удалось.

Вы можете использовать strace , чтобы узнать, какие системные вызовы выполняет ваш сервер или какой-либо другой.,Конечно, используйте также отладчик gdb.

Скорее всего, вам нужно мультиплексировать входы или выходы.При этом выполняются системные вызовы: poll , select (и связанные ppoll и pselect).Прочтите, например, справочную страницу select_tut (2) .

Вы можете использовать (или хотя бы изучить исходный код) существующие библиотеки, ориентированные на события, такие как libevent, libevи т. д. (Платформы Gtk и Qt предоставляют также свои собственные, которые могут использоваться даже вне приложений с графическим интерфейсом).

Я настоятельно рекомендую прочитать о расширенном программировании Unix и unixсетевое программирование (и, возможно, также расширенное программирование в Linux ).

0 голосов
/ 27 мая 2016

Я думаю, что я довольно поздно на вечеринке, но я думаю, что этот ответ может кому-то помочь.

Если на передающем сокете нет места для хранения сообщения, подлежащего передаче, и дескриптора файла сокетане имеет установленного O_NONBLOCK, send () должен блокировать, пока не освободится место.

Когда функция send () застревает, может возникнуть ситуация, например, размер окна TCP стал равным 0. Это происходит, когда другой конецсоединения не использует полученные данные.

Возможен сценарий, подобный этому, процесс принимающей стороны выполняется GDB и произошел сбой.

  1. Соединение TCP остается установленным.
  2. Данные отправляются непрерывно.
  3. Конец получателя не использует его.

Следовательно, размер окна TCP получателя будет уменьшаться, и вы сможете отправлять данные, пока он не станет больше нуля.Как только она становится равной 0, функция send () застревает навсегда.

Поскольку упомянутая в вопросе ситуация не является сценарием замкнутого соединения.Когда процесс записывает что-то в закрытое TCP-соединение, он получает сигнал SIGPIPE.Обработчик по умолчанию SIGPIPE завершает процесс.Таким образом, в сценарии закрытого соединения, если вы не используете свой собственный обработчик SIGPIPE, тогда процесс должен завершаться обработчиком по умолчанию всякий раз, когда что-то записывается в сокет.

0 голосов
/ 12 февраля 2012

со страницы руководства: в send () не указано, что не удалось выполнить доставку.Локально обнаруженные ошибки обозначаются возвращаемым значением -1.

Вероятно, что-то подобное может помочь: http://stefan.buettcher.org/cs/conn_closed.html

0 голосов
/ 12 февраля 2012

возможно, вы используете протокол tcp, а сервер ожидает ACK.Попробуйте использовать UDP, если вы хотите, чтобы ваше соединение было асинхронным.

...