LINUX.ORG.RU

раздумья о передачи данных по socket'у


0

0

Привет, всезнающий all ;).

Клиент передает данные серверу. Варианты передачи :

1.
client.send ( data1 );  server.recv ( data1 ); 
server.send ( "data1 ok" );  client.recv ( strOk );
...
client.send ( data10 ); server.recv ( data10 );
server.send ( "data10 ok");   client.recv ( strOk );

Подтверждение нужно для того чтобы данные не слились в один поток.

2.
client.send ( countOfData ); server.recv ( countOfData );
server.send ( "OK" ); client.recv ( strOk );
client.send ( allData ); client.close();
server.recv ( allData ); parse ( allData );

Здесь послыается все данные скопом, но тогда серверу приходится их
"парсить", какой вариант вы посоветуете? Или быть может есть третий?

Спасибо.

anonymous

TCP - потоковый протокол. Если речь идёт о нём, то с данными следует работать только как с однородным потоком. Конечно это не всегда удобно, зато эффективно и правильно.

Посмотри ещё раз на свой "вариант 1". Во-первых, ты вводишь лишнее подтверждение приёма данных: в TCP одно уже есть. Во-вторых, ты сильно ограничиваешь скорость передачи: вместо того, чтобы просто отправить все данные одновременно (или ту их большую часть, которая помещается в окно TCP), ты выполняешь двусторонний обмен. Представим, что передача идёт через спутник и в один конец данные идут две секунды (а самих данных мало, так что пакет передаётся за малое время + эти 2 сек). У тебя десять "пакетов" - и вместо 2 с на передачу ты тратишь 2 * 10 + 2 * 9 = 38 секунд :()

erDiZz
()

да, мой опыт подсказывает что лучше всего отдавать данные сплошным 
потоком иначе можешь нелететь на "непонятно что", а именно на ту
же фрагментацию пакетов.

В перле я напиример делал так сервер:

my $texts={};
my $serv=new IO::Socket::INET(...);
my $sel=new IO::Select();
$sel->add($serv);
while (1) {
   foreach my $cli ($sel->can_read()) {
      if ($cli eq $serv) { # Новое соединение
         $cli=$serv->accept();
         $texts->{$cli}="";
         $sel->add($cli);
      } else { # Пришли какие-то данные?
         my ($tmp,$size);
         $size=$cli->recv($tmp,1024);
         if (defined $size && $size>0) {#Действительно пришли
            $texts->{$cli}.=$tmp; # Добавляем данные в конец
            work($texts,$cli);
         } else {#На самом деле разрыв соединения
            delete $texts->{$cli};
            $sel->remove($cli);
         }
      }
   }
}

sub work {
   my ($texts,$cli)=@_;
   # Првоверяем есть ли полная фраза и если есть удаляем её
   # из буффера
   if ($texts->{$cli}=~s/^(Some full frase)//) {
       $cli->send("Some answer");# Send some data
   }
}

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

А что вы посоветуете для С++? Имеется ли "лекгий класс" (обретка для сокетов)? Можно конечно свою написать, но как-то устал быть велосипедистом.

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

лёгкий класс займёт у тебя килобайт 10 отсилы - проще самому писать
чем тащить за собой тот же QT. И быстрее написать чем найти в гугле :)

vahvarh ★★★
()

лучше обрамлять каждый нужный кусок данных в пакет,
куда помещать тег, длинну и прочую мета-информацию,
тогда и процедура приёма/проверки будет проще и парсить ничего не надо.
(далее следует пример на C, просто демонстрирующий принцип)

struct header {
 uint_32 tag;
 uint_32 len;
 // uint_32 crc; // optional - control sum
}__attribute__((packed));

/* send data - create and send data header, before udata */
int send_data(int sock,uint_32 tag,uint_32 len,void *data) {
  struct header header;
  assert(sock>=0);
  assert(data!=NULL);
  header.tag=htonl(tag);
  header.len=htonl(len);
  if (write(sock,sizeof(header),&header)!=sizeof(header) &&
   write(sock,len,data) != len)
   return 0;
  return -1;
}
/* recv data - first receive and parse header */
int recv_data(int sock,uint_32 *ptag,uint_32 *len,void *data) {
  struct header header;
  assert(sock>=0);
  assert(ptag!=NULL);
  assert(len!=NULL);
  assert(data!=NULL);
  if (read(sock,sizeof(header),&header)<0)
    return -1; // unable to receive header
  header.len=ntohl(len);
  if (header.len>(*len))
    return -1; // receiver buffer is too small
  if (header.len!=0 && read(sock,header.len,data)!=header.len)
    return -1; // error on receive data
  // if need - check control sum (omitted in this example)  
  (*ptag)=ntohl(header.tag);
  (*len)=header.len;
  return 0;
}
/**small peice of client (send data to server) */
if (send_data(sock,TAG_PASSWORD,pass_length,password)!=0 &&
send_data(sock,TAG_LOGNAME,strlen("anybody"),"anybody")!=0) {
 // login data sended, awaiting answer
}

/** small piece of server (read data from client) */
uint_32 len;
len=sizeof(buffer);
if (read_data(sock,&tag,&len,buffer)!=0) {
  if (tag==TAG_LOGNAME) {
   // store logname
   logname_received=1;
  } elseif (tag==TAG_PASSWORD) {
   // store password
   pass_received=1;
  }
  if (logname_received && pass_received) {
   // check password
  }
}

P.S. код не тестировался, и даже не пробовался - написан с руки и содержит ошибки.

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