LINUX.ORG.RU

Признак окончания связи в tcp-соединении


0

0

Хочу написать программу, которая прозрачна для тсп-соединения(пока деляю как клиента). Сделал socket(), bind(), connect() - все здорово, начинаю слушать сервер(recv()) и посылать ему сообщения(send()). Все это делаю на локальной машине, организовав бесконечный цикл, но вот до условия, чтобы из него выйти, додуматься пока не могу, т.е. программу приходится покидать через CTRL+C. Вопрос - есть ли стандартная последовательность символов, одинаковая и для smtp, pop3, telnet и т.д., наличие которой однозначно говорит о том, что сервер соединение прекратил? Может, кто сталкивался с такой проблемой? Также буду благодарен за ссылки, которые содержат нужную инфу. Мой ящик - gorikh@ingos.ru. P.S. - речь шла о С

anonymous

если recv() вернул 0 то это означает что на том конце нормально закрыли сокет. К сожалению ты не сможешь узнать о закрытии сокета на том конце во время send(), но через некоторое время ты можешь словить сигнал SIGPIPE и обработать его .. вобщем обычно делают так: вешают select() на read из сокета, а посылают просто через send(), после закрытия сокета на том конце selec() вываливается и read возвращает 0, что и означает что там закрыли сокет.

кстати почитал бы что-либо про сокеты - тема давно затертая

PS: SMTP, POP3 и TELNET тут не причем, ты же не собираешься каждый раз проверять что они тебе там присылают и сравнивать с какой-либо магик строкой? :)

lg ★★
()
Ответ на: комментарий от lg

спасибо, lg, я вместо бесконечного цикла организовал цикл while(recv(sock, buf, sizeof(buf), 0)), но есть одна кривизна. До тех пор, пока сервер шле ответы в одну строку, все нормально, но когда они состоят из нескольких строк, то для получения продолжения приходится нажимать ENTER а он записывается в буфер команд, соответственно возникают ошибки. Каким образом можно считать в буфер ВЕСЬ ответ сервера, игнорируя символы новой строки ? И где можно почитать про сокеты доходчиво? Я читал Робачевского, там доходчиво, но мало

anonymous
()
Ответ на: комментарий от anonymous

вот тебе цикл, который принимает сообщение целиком и держит его в
памяти.
цикл for(i=0; i<nbytes; i++) answer[len+i] = buffer[i]; можно
заменить на что-нибудь в роде strcat()
это я писал для граббера. нравится - юзай, не нравится - не надо :)


char *answer, buffer[size];
int i, sd, len, nbytes;
/* устанавливаешь соединение и отправляешь запрос */
nbytes = 0;
do
{
	nbytes = recv(sd, buffer, sizeof(buffer), 0);
	buffer[nbytes] = '\0';
	if(answer == NULL) len = 0;
	else len = strlen(answer);
	answer = (char*)realloc(answer, (len+nbytes+1)*sizeof(char));
	for(i=0; i<nbytes; i++) answer[len+i] = buffer[i];
	answer[len+nbytes] = '\0';
}while (nbytes>0);

NikZ
()

что значит весь? то есть до того момента пока в течении 
определенного времени он ничего не посылает?

такой while не катит так/как recv может вернуть -1 что 
будет означать ошибку которую надо конкретно обрабатывать
и выходить из while

обычно пишут так:

while (1) {
   n = select(nfds, &rfds, 0, 0, tvto);

   if (n < 0) {
        if (errno == EINTR || errno == EAGAIN)
            continue;
        break;
   }

   if (n == 0) {
       /* select timeouted */

       /* TODO: обработчик таймаута */
   }
   
   if (n > 0 && FD_ISSET(sock, &rfds)) {
       /* sock is ready to recv */
       rb = recv(sk, buf, maxlen, flags);
       if (rb == 0) {
           /* тот конец закрыл соединение */
           verbose("[V] peer closed connection ..\n");
           break;
       }
       if (rb < 0) {
           /* TODO: errno checks */
           break;
       }

       /* теперь буффер содержить какую то инфу */

       /* 
        * TODO: всяческие проверки на полезность и
        *       достаточность этой инфы с возможным
        *       проставлением всяческих флагов или
        *       что необходимо для работы
        */

        buf[rb] = '\0';
        cmd = parse_buf(buf, &intern_sk_state);
        err = do_action(sock, cmd, &intern_sk_state);
        
        /* TODO: err checking */

        /* TODO: etc .. */
   }
}

/* .... */
int
do_action(int sock, int cmd, int *iss)
{
    switch (cmd) {
      case CMD_LIST:
          if (*iss & ISS_WAIT_LIST) {
             /* TODO: LIST action */
             *iss &= ~ISS_WAIT_LIST;
             *iss |= ISS_LIST_DONE;
          } else {
             /* TODO: states
             return -1;
          }
          break;
      case CMD_WHATEVER_YOU_WANT:
          /* TODO: WHAT EVER YOU WANT action */
          send(sock, "+OK WEYW DONE.\r\n", sizeof("+OK LIST DONE.\r\n", 0);
          break;
      case CMD_UNKNOWN:
      default:
          /* TODO: unknown command action */
          verbose("[W] Unknown command from server\n");
          return -1;
 
     }
     return 0;
}


почитать можно:
  [1] man recv
  [2] man send
  [3] man select
  [4] man socket
  [5] man tcp

lg ★★
()
Ответ на: комментарий от NikZ

В принципе понял, спасибо большое. Однако на самом деле проблема еще и в том, что определенные команды подаются не в несколько строк(со строками, как я внимательно посмотрел, нет проблем), а в несколько приемов, т.е. обычный клиент в промежутке между ними наверняка посылает какие-то команды. Где можно найти всевозможные RFC ?

anonymous
()

Почитать хорошо книгу "Эффективное программирование ТСР-IP".

ansky ★★★★★
()

В принципе TCP это поток-ориентированный протокол и он не передаёт границы сообщений, а гарантирует только правильную последовательность данных. И передаёт он их не с построчной буферизацией. Анализ данных - не его задача, решается она на более высоком уровне. В случае командных строк клиент сам должен сканировать свой приёмный буфер на предмет СR|LF и на основе этого парсить принимаемый от сервера поток. А если команды могут быть многострочными, ну уж... тогда и анализ должен быть посложнее - можно, например шелл прикрутить ;)

Loki
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.