2012-02-12 4 views
0

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

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); 
    } 

Благодаря

+0

Показать еще код пожалуйста. – ThiefMaster

ответ

1

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

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

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

Вам, вероятно, необходимо мультиплексировать входы или выходы. Системные вызовы - poll, select (и связанные с ними ppoll и pselect). Чтение, например. справочная страница select_tut(2).

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

Я настоятельно рекомендую прочитать около advanced unix programming и unix network programing (и, возможно, также около advanced linux programming).

+0

Обычно люди не могут использовать подобные libs в домашних заданиях. Это в значительной степени победит цель работы с низкоуровневыми функциями сокетов и узнает, как их использовать. – ThiefMaster

+0

Но они могут хотя бы изучить их исходный код и многому научиться. –

+0

Действительно - но для простого назначения это обычно слишком сложно. – ThiefMaster

0

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

+0

Это часть моего сетевого задания, и я должен использовать TCP –

0

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

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

+0

Пример показывает, что сервер получает что-то от клиента, и если в трубе ничего нет, он рассматривает закрытие клиента. Но в моей программе клиент закрывается, когда сервер отправляет данные клиенту. моя программа сервера останавливается в функции send(). и флаги приема не работают с функцией send(). –

0

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

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

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

Возможно, существует такой сценарий, что процесс завершения приема выполняется GDB и произошел segfault.

  1. TCP-соединение остается установленным.
  2. Данные отправляются непрерывно.
  3. Терминал приемника не потребляет его.

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

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

Смежные вопросы