2015-12-30 3 views
0

Я написал простое tcp/ip соединение client-server в c++.C++ читать неизвестный объем данных из сокета

Это часть сервера, который обрабатывает соединительном

int sockfd, newsockfd; 
socklen_t clilen; 
struct sockaddr_in serv_addr, cli_addr; 
int n = 0; 

sockfd = socket(AF_INET,SOCK_STREAM,0); 
if(sockfd < 0){ 
    cout << "Error opening socket" << endl; 
    exit(1); 
} 

bzero((char*)&serv_addr, sizeof(serv_addr)); 

serv_addr.sin_family = AF_INET; 
serv_addr.sin_addr.s_addr = INADDR_ANY; 
serv_addr.sin_port = htons(portno); 

if(bind(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr))<0){ 
    cout << "Error binding" << endl; 
    exit(1); 
} 

listen(sockfd,1); 
clilen = sizeof(cli_addr); 

newsockfd = accept(sockfd,(struct sockaddr *)&cli_addr, &clilen); 

if(newsockfd < 0){ 
    cout << "Error accepting" << endl; 
    exit(1); 
} 

bzero(bytes,size_tot); 
uint64_t total_bytes_read = 0; 
uint64_t total_bytes_to_read = size_tot; 
while(total_bytes_read < total_bytes_to_read){ 
    int bytes_read = read(newsockfd,bytes + total_bytes_read,total_bytes_to_read - total_bytes_read); 
    if(bytes_read == -1){ 
     cout << "error reading "<< endl; 
     n = -1; 
     break; 
    } 
    total_bytes_read += bytes_read; 
} 

, но это работает, если я знаю, что общее количество байтов для чтения. Что делать, если общий объем данных для чтения неизвестен? Как я могу изменить этот кусок кода?

+0

Похоже, что этот вопрос неоднозначен, и это приводит к противоречивым ответам. Не совсем понятно, что вы хотите прочитать. Вы хотите прочитать все байты, пока другая сторона не закроет соединение? Или что? –

+0

Я считаю, что вопрос совершенно ясен, и OP спрашивает, как вообще иметь дело с случаем, когда размер передачи неизвестен заранее. – SergeyA

+0

Тогда мой ответ был точно верным. Вы просто вызываете 'read' без цикла, ожидающего определенного количества байтов. (Его вопрос заключался в том, как модифицировать код приема на низком уровне, а не как писать код протокола высокого уровня.) –

ответ

3

Вы спрашивали, как исправить ваш код приема на низком уровне. Это просто - просто позвоните по номеру read и не используйте цикл while. Вызов read будет возвращен, как только будет прочитан хотя бы один байт данных. Для количества прочитанных байтов просто передайте размер вашего буфера (или оставшееся место в нем, если в нем уже есть остатки от предыдущего вызова).

Вам также понадобится код протокола высокого уровня, как и вы, если знаете количество байтов. Возможно, этот код будет немного отличаться. Если кусок байтов, который вы получили, включает в себя индикацию остановки, затем обработайте все байты до индикации остановки и сохраните лишний в буфере в следующий раз. Если нет, просто позвоните read и получите кучу больше байтов.

Ваш протокол код обработки должен выглядеть вроде этого:

  1. вызов read и добавить однако количество байтов, которые вы получили в буфер. (Обращайтесь к ошибке или нормальному закрытию здесь.)
  2. Если данные в буфере не содержат индикацию останова, перейдите к шагу 1.
  3. Обработать все байты до индикации остановки.
  4. Удалите обработанные байты из буфера, оставив необработанные байты.
  5. Перейти к шагу 2.

Кроме того, код, который вы дали в этом вопросе будет вращаться вечно, если другая сторона закрывает соединение. В этом случае read вернет ноль, и вы никогда не сможете читать больше данных из соединения. Вы должны выйти из цикла, если read возвращает ноль.

+1

'read' не гарантированно возвращает все данные - только его вызов один раз не является полным решением. – user2864740

+0

@ user2864740 Я не знаю, что вы подразумеваете под «всеми данными». Все * какие * данные? –

+1

Все данные для .. читать (из любого соединения). – user2864740

2

Прежде всего, избавитесь от всех звонков bzero. Я не знаю, почему это держится в коде хорошего человека. Существует нуль, nada, nicht нужно для этого.

Прежде всего, вам нужно как-то заранее сообщить размер передачи - например, HTTP 1.1 предоставляет эту информацию в заголовке или просто заявляет, что соединение закрывается после того, как все данные были переданы - это будет модель HTTP 1.0.

+0

Этот ответ, похоже, не затрагивает вопрос, заданный ОП. Он спросил, как называть 'read', когда он не знает, сколько байтов ему нужно прочитать. –

+0

@ Давид, НЕТ. Вы неправильно поняли этот вопрос, и теперь вы заманиваете меня за то, что я правильно понял. – SergeyA

+0

Он спросил, как изменить свой код, чтобы обработать случай, когда он не знает, сколько байтов он хочет прочитать. Это очень просто - просто не продолжайте цикл, пока не получите определенное количество байтов. –

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