2014-02-03 2 views
0

Я установил простую клиентскую и серверную программу, используя TCP-сокет для связи. Сервер ожидает, что клиент подключится и ответит, получает ли он сообщение от клиента. Ниже, как код реализован на сервере и клиенте:Как узнать, что send() или sendmsg() успешно доставляют сообщение?

кода на стороне сервера:

listen(sockfd,5); 

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

if (newsockfd < 0) 
     error("ERROR on accept"); 
bzero(buffer,256); 

n = read(newsockfd,buffer,255); 

if (n < 0) 
    error("ERROR reading from socket"); 

printf("Here is the message: %s\n",buffer); 

n = write(newsockfd,"I got your message",18); 

if (n < 0) 
    error("ERROR writing to socket"); 

кода на стороне клиента:

if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) 
    error("ERROR connecting"); 
printf("Please enter the message: "); 
bzero(buffer,256); 
fgets(buffer,255,stdin); 
n = write(sockfd,buffer,strlen(buffer)); 
if (n < 0) 
    error("ERROR writing to socket"); 
else 
    printf("sucess. n = %d", n); 

bzero(buffer,256); 
n = read(sockfd,buffer,255); 
if (n < 0) 
    error("ERROR reading from socket"); 

Теперь предположим, что Я запускаю сервер, а затем запускает клиент, клиент успешно подключается к серверу. Затем я закрываю сервер и пытается отправить сообщение от клиента, операция write() не возвращает ошибку. То, что я ожидаю здесь, является ошибкой, потому что сервер фактически не получает никаких пакетов (он отключается).

Так что мой вопрос: есть ли способ узнать, успешно поставляет ли write() (или send(), sendto() или sendmsg()) сообщение на сервер?

+0

Многие люди спрашивают: «Если стек TCP знает, что этот пакет был подтвержден (ACK'd) удаленным хостом, почему мой код приложения не может определить это?» Причина в том, что TCP знает только, был ли пакет ACK'd уровнем TCP удаленного узла. Он не знает, действительно ли подтвержденные данные были фактически использованы приложением, размещающим сокет на удаленной стороне. Следовательно, прототипы более высокого уровня выше TCP (т. Е. Ваш код и протокол) должны обеспечивать эту сигнализацию. – selbie

ответ

1

Это не работает. write() возвращает успех, как только сообщение вписывается в буфер отправки. Единственный способ узнать, что сообщение было получено и обработано сервером, получает синтаксический анализ «Я получил ваше сообщение».

write() возвращает -1, тогда соединение уже известно, что оно закрыто или недействительно, но не рассчитывайте на это, чтобы обнаружить все возможные ошибки.

+0

Первый абзац верен, но во втором абзаце слишком много дезинформации. write() возвращает только ноль, если вы передаете нулевую длину. Если вы вызываете его в закрытом сокете, он возвращает -1 с переменной errno, установленной в EBADF. Если вы вызываете его по соединению, которое было закрыто одноранговым узлом, оно возвращает -1 с errno, установленным в ECONNRESET. -1 сам по себе не указывает «недействительное соединение». – EJP

+0

Спасибо за исправление! – epx

+0

Ну, идея состоит в том, чтобы исправить ответ на самом деле. – EJP

3

№ Напишите или отправьте сообщение просто, они не ждут обратной связи (например, ACK в случае TCP). Но вы можете быть уверены, что сообщение было успешно отправлено, если вы получили какую-то обратную связь. Это даже не помогает попробовать другую отправку, потому что она может быть выполнена, пока предыдущее сообщение еще не находится на клиенте. Это также не помогает найти и надеяться на ошибку, потому что полученные вами данные могут быть отправлены одноранговым узлом, прежде чем вы даже отправите свое сообщение. Единственный способ быть уверенным в том, чтобы поставить какое-то явное рукопожатие в ваш протокол приложений и дождаться ответного ответа на ваше сообщение.

+0

Я искал эту проблему, и кажется, что когда сервер остановился, на клиент отправляется сигнал SIGPIPE, но я до сих пор не знаю, как клиент ловит и обрабатывает этот сигнал. –

+2

Вид: если соединение TCP закрыто, и вы пытаетесь отправить() или write() снова, вы получаете SIGIPE или если вы игнорируете сигнал, системный вызов возвращает EPIPE. Но это не так, что сервер отправляет сигнал клиенту, он просто закрывает соединение. –