Поведение отправки UDP после connect () - PullRequest
8 голосов
/ 09 декабря 2010
#include <stdio.h>  
#include <errno.h>  
#include <stdlib.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  

int main()  
{    
    struct sockaddr_in addr;  
    int fd, cnt,ret;  
    char ch = 'y',msg[] ="How are you";  

    if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0) {  
        printf("Error: socket");  
        exit(1);  
    }
    printf("\nDone socket\n");  

    /* set up destination address */  
    memset(&addr,0,sizeof(addr));  
    addr.sin_family=AF_INET;  
    addr.sin_addr.s_addr=inet_addr("128.88.143.113");  
    addr.sin_port=htons(9090);  

    ret=connect(fd,(struct sockaddr *)&addr,sizeof(addr));  
    perror("Connect:");  

    while(ch == 'y'){  
        cnt =  send(fd,msg,sizeof(msg),0);  
        if(cnt < 0)  
        perror("send:");  
        printf("\nNumber of bytes sent = %d , \n",cnt);  
        printf("Continue (y/n)\n");  
        scanf(" %c",&ch);  

     }

     return 0;  
}  

Приведенный выше код скомпилирован для запуска на компьютере с Linux.

Предположим, что приведенный выше код отправляет данные на компьютер с IP-адресом 128.88.143.113.UDP-сокет не привязан к порту 9090 в 128.88.143.113.

В цикле while первый вызов к send() завершается успешно (пакет фактически выходит из сети; проверил его с помощью trace), а второй send() завершается с Connection refused.third send() завершается успешно, четвертый - и т.д.структура сокетов.Второй send() терпит неудачу при обнаружении этой ошибки, и фактически пакет не отправляется.Второй send() также очищает ошибку в структуре сокета.Поэтому третий send() успешен, а четвертый - неудачен и т. Д.

Вопросы:

  1. Верно ли это предположение?
  2. Каким должно быть правильное поведение?Существует ли какой-либо стандарт RFC, определяющий такое поведение?
  3. Поскольку UDP не поддерживает никакого состояния соединения, разве не каждый send() должен быть успешным?

Ответы [ 5 ]

5 голосов
/ 09 декабря 2010

Согласно справочной странице linux для udp :

Все фатальные ошибки будут переданы пользователь в качестве ошибки вернется, даже когда розетка не подключена. Это включает асинхронные ошибки, полученные от сеть. Вы можете получить ошибку для более ранний пакет, который был отправлен на та же розетка. Это поведение отличается от многих других BSD сокетов реализации, которые не проходят ошибки, если сокет не подключен. Поведение Linux предписано RFC 1122 .

В частности, RFC (4.1.3.3) гласит:

UDP ДОЛЖЕН передать на прикладной уровень все ошибки ICMP сообщения, которые он получает от уровня IP. Концептуально по крайней мере, это может быть достигнуто с помощью ERROR_REPORT рутина

3 голосов
/ 09 декабря 2010

Ваша гипотеза верна.Справочная страница Linux udp (7) описывает ситуацию следующим образом:

Все фатальные ошибки будут переданы пользователю в виде сообщения об ошибке, даже если сокет не подключен.Это включает в себя асинхронные ошибки, полученные из сети.Вы можете получить ошибку для более раннего пакета, который был отправлен в тот же сокет.
Это поведение отличается от многих других реализаций сокета BSD, которые не пропускают никаких ошибок, если сокет не подключен.Поведение Linux предписывается RFC 1122 .

Когда опция IP_RECVERR включена, все ошибки сохраняются в очереди ошибок сокета и могут быть получены recvmsg(2) с помощью MSG_ERRQUEUEфлаг установлен.

2 голосов
/ 09 декабря 2010

Было бы интересно сравнить эквивалентный код, используя sendto() вместо connect() и send().

Является ли показанный код таким же образом, если вы оставляете промежуток времени между каждой отправкой, то есть состояние ошибки ICMP, сохраняемое в сокете в течение некоторого периода времени, или он все равно будет отказывать во втором send() если вы оставили это, скажем, час?

Я ожидаю, что ваше предположение верно, сетевой стек пытается быть умным. Нет другого момента, когда он мог бы вернуть «отказано в соединении», так как при отправке вызова connect() ничего не отправляется, он просто сохраняет заданный адрес, так что сокет «логически» подключен, и тогда вызовы на send() могут работать.

1 голос
/ 09 декабря 2010

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

0 голосов
/ 12 января 2017

У меня была такая же проблема;и это связано с тем, что очередь сообщений udp заполняется, если никто не слушает и не очищает очередь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...