Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Интересная особенность sendto()

3.3K
08 августа 2006 года
GENA_DJ
123 / / 08.03.2005
ws2_32.dll

Как результат работы sendto() может быть ошибка сокета, делающая невозможным дальнейшую работу. WSAGetLastError() возвращает при этом WSAECONNRESET.

[QUOTE=MSDN]WSAECONNRESET: The virtual circuit was reset by the remote side executing a "hard" or "abortive" close. For UPD sockets, the remote host was unable to deliver a previously sent UDP datagram and responded with a "Port Unreachable" ICMP packet. The application should close the socket as it is no longer usable.[/QUOTE]

На этот счет вопрос: как сделать UDP сокет нечувствительным к подобного рода ошибкам. Это необходимо для того, чтобы не открывать на машине лишних портов, в то время как отновной порт был все время открыт и доступен.
6.8K
08 августа 2006 года
Romikgy
84 / / 28.04.2005
[QUOTE=GENA_DJ]ws2_32.dll

Как результат работы sendto() может быть ошибка сокета, делающая невозможным дальнейшую работу. WSAGetLastError() возвращает при этом WSAECONNRESET.



На этот счет вопрос: как сделать UDP сокет нечувствительным к подобного рода ошибкам. Это необходимо для того, чтобы не открывать на машине лишних портов, в то время как отновной порт был все время открыт и доступен.[/QUOTE]
А на кой в юдп использовать ассинхроный сокет?????
создай поток слушающий порт с юдп,
и создавай времено сокет для передачи юдп месаги
3.3K
09 августа 2006 года
GENA_DJ
123 / / 08.03.2005
[QUOTE=Romikgy]А на кой в юдп использовать ассинхроный сокет?????[/QUOTE]
Я ни слова не говорил, что сокет является асинхронным.
[QUOTE=Romikgy]создай поток слушающий порт с юдп, и создавай времено сокет для передачи юдп месаги[/QUOTE]
Я написал, что не хочу открывать лишних портов. К тому же сам факт возникновения такой ошибки дает дополнительную уязвимость: если ты хочешь закрыть на удаленной машине UDP порт, просто пошли ICMP с "Port Unreachable".
6.8K
09 августа 2006 года
Romikgy
84 / / 28.04.2005
[QUOTE=GENA_DJ]Я ни слова не говорил, что сокет является асинхронным.

Я написал, что не хочу открывать лишних портов. К тому же сам факт возникновения такой ошибки дает дополнительную уязвимость: если ты хочешь закрыть на удаленной машине UDP порт, просто пошли ICMP с "Port Unreachable".[/QUOTE]
да насчет асинхроного ступил ,звыняюсь :)
А о каком лишнем порту речь?
и насчет ICMP не совсем догнал :(
3.3K
09 августа 2006 года
GENA_DJ
123 / / 08.03.2005
[QUOTE=Romikgy]
А о каком лишнем порту речь?
[/QUOTE]
Ты же сам говоришь:
[QUOTE=Romikgy]
создавай времено сокет для передачи юдп месаги
[/QUOTE]

[QUOTE=Romikgy]
и насчет ICMP не совсем догнал :(
[/QUOTE]
Если при попытке отправить UDP - пакет я получаю ICMP - пакет об отказе, это значит, что отправляющий сокет становится недоступным для дальнейшей работы.

Переформулирую вопрос. Как сделать "всегда живой" UDP сокет, по которому я могу как передавать, так и принимать пакеты независимо от того, может ли адресат их принять или нет?
10K
10 августа 2006 года
Sonic_amiga
34 / / 19.06.2006
UDP-сокет всегда живой. ECONNRESET может выдаваться только для TCP-сокета, т. к. только для него существует понятие соединения. UDP-сокет просто тупо плюется пакетами и все, ему пофиг принял их кто-нибудь или нет, он даже об этом не знает.
6.8K
10 августа 2006 года
Romikgy
84 / / 28.04.2005
Приведи исходник , а то действительно получается что ты юзаешь TCP пакет а не UDP
3.3K
10 августа 2006 года
GENA_DJ
123 / / 08.03.2005
[QUOTE=Romikgy]Приведи исходник , а то действительно получается что ты юзаешь TCP пакет а не UDP[/QUOTE]

ПО №1
Код:
#include<stdio.h>
#include<windows.h>
int main(int argc, char * argv[])
{
#define blen 0x4000

    struct WSAData
        WSAData;

    SOCKADDR_IN
        loca_sin,
        dest_sin;

    SOCKET
        sock;

    int
        fromlen,
        len;
    char
        sb[blen];

    if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0)
    {
        return 0;
    }
    if((sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==INVALID_SOCKET)
    {
        WSACleanup();
        return 0;
    }
    loca_sin.sin_family = PF_INET;
    loca_sin.sin_addr.s_addr = inet_addr("127.0.0.1");//Можно и INADDR_ANY поставить, если работать со всеми интерфейсами
    loca_sin.sin_port = htons(66);//можно и 0 поставить, если порт назначать динамически

    if(bind(sock,(LPSOCKADDR)&loca_sin,sizeof(loca_sin))==SOCKET_ERROR)
    {
        closesocket(sock);
        WSACleanup();
        return 0;
    }

    for(;;)
    {
        dest_sin.sin_family = AF_INET;
        dest_sin.sin_addr.s_addr = inet_addr("127.0.0.1");//Можно и любой другой адрес поставить
        dest_sin.sin_port = htons(99);
        if(sendto(sock, sb, blen, 0, (LPSOCKADDR)&dest_sin, sizeof(dest_sin))==SOCKET_ERROR)
        {
            closesocket(sock);
            WSACleanup();
            return 0;
        }
        printf("sent\n");
        fromlen=sizeof(dest_sin);
        if((len=recvfrom(sock, sb, 0x4000, 0, (LPSOCKADDR)&dest_sin, &fromlen))==SOCKET_ERROR)
        {
            closesocket(sock);
            WSACleanup();
            return 0;
        }
        printf("recived\n");
    }
    closesocket(sock);
    WSACleanup();
    return 0;
}


ПО №2
Код:
#include<stdio.h>
#include<windows.h>
int main(int argc, char * argv[])
{
    struct WSAData
        WSAData;

    SOCKADDR_IN
        loca_sin;

    SOCKET
        sock;

    if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0)
    {
        return 0;
    }
    if((sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==INVALID_SOCKET)
    {
        WSACleanup();
        return 0;
    }
    loca_sin.sin_family = PF_INET;
    loca_sin.sin_addr.s_addr = INADDR_ANY;
    loca_sin.sin_port = htons(99);

    if(bind(sock,(LPSOCKADDR)&loca_sin,sizeof(loca_sin))==SOCKET_ERROR)
    {
        closesocket(sock);
        WSACleanup();
        return 0;
    }
    Sleep(1000*60*1);
    return 0;
}


С ПО №2 всё просто. Оно открывет порт 99 и ждёт минуту.

ПО №1 открывает порт 66, в цикле шлёт порту 99 пакет, затем recvfrom() ожидает данные на порту 66. Если данные приняты, то переход к следующей итерации.

Симптомы.
Если ПО №2 запущено, то ПО №1 работает так, как и должно. Если ПО №2 не запущено (порт 99 не открыт), то ПО №1 вылетает на recvfrom() с SOCKET_ERROR

WSAGetLastError() возвращает при этом WSAECONNRESET

Если верить MSDN, то это вызвано тем, что
Цитата:

For UPD sockets, the remote host was unable to deliver a previously sent UDP datagram and responded with a "Port Unreachable" ICMP packet. The application should close the socket as it is no longer usable.



Вопрос такой.

Как сделать UDP сокет, стойкий к "Port Unreachable" ICMP packet?

Одно решение уже придумалось - использовать RAW Socket для отправки, а RCV_ALL для приёма. Данный метод неприемлем, особенно RCV_ALL. К тому же RAW Socket имеет проблему совместимости, а также требует административных привилегий учетной записи для запуска ПО.

6.8K
10 августа 2006 года
Romikgy
84 / / 28.04.2005
1. у тя проблемы с размерами , имхо,
For message-oriented sockets, care must be taken not to exceed the maximum packet size of the underlying subnets, which can be obtained by getting the value of socket option SO_MAX_MSG_SIZE.
2. я бы сделал широковещательную передачу
3. насколько я понял сокет у тя блокирующий, а ты его в основном потоке крутишь, висяк проги имхо обеспечен
3.3K
10 августа 2006 года
GENA_DJ
123 / / 08.03.2005
[QUOTE=Romikgy]1. у тя проблемы с размерами , имхо,
For message-oriented sockets, care must be taken not to exceed the maximum packet size of the underlying subnets, which can be obtained by getting the value of socket option SO_MAX_MSG_SIZE.
[/QUOTE]
Это я понимаю. Насколько я помню, я тестил и с маленькими пакетами < 512 байт, результат аналогичен. Через некоторое время уточню.

[QUOTE=Romikgy]
2. я бы сделал широковещательную передачу
[/QUOTE]
Незачем, нужна связь точка-точка.(Причем с фиксированными номерами портов). Если ты знаешь, есть такое ПО http://openvpn.net/ Одна из возможных конфигураций такова, что на каждом хосте открыт единственный UDP порт, который служит как для приема, так и для передачи.

[QUOTE=Romikgy]
3. насколько я понял сокет у тя блокирующий, а ты его в основном потоке крутишь, висяк проги имхо обеспечен
[/QUOTE]
"Висяк" то в данном примере мне и нужен. Если порт назначения открыт, то все пучком. Но если получатель недоступен, то после посылки сокет "умирает" при попытках на нём данные принять.
4.8K
10 августа 2006 года
xm...
45 / / 20.11.2004
Винда какая? Если 2000, то читай MSDN, там написано, что удп сокеты могут при приеме возвращать WSAECONNRESET.
Статья: Q263823 WinSock Recvfrom() Now Returns WSAECONNRESET Instead of Blocking or Timing Out.
Решение: Установка hotfix'a. И ваще, если у тебя 2000, то нафиг его, переходи на XP =) Там таких траблов у меня не было.
6.8K
10 августа 2006 года
Romikgy
84 / / 28.04.2005
тогда чего заморачиваешься с юдп делай на тсп, плюс надежность возврастет
3.3K
10 августа 2006 года
GENA_DJ
123 / / 08.03.2005
[QUOTE=xm...]Винда какая?[/QUOTE]
2003 SERVER EE
[QUOTE=Romikgy]
делай на тсп
[/QUOTE]
не хотел бы ... из соображений скорострельности как минимум. Теперь уже задумался.

Вопрос причины остался нерешенным. Буду искать.
4.8K
10 августа 2006 года
xm...
45 / / 20.11.2004
не закрывай сокет после ошибки вот и всё, зачем его закрывать? это же удп. дальше идет посылка sendto без всяких ошибок: только что сам попробовал твой код "ПО №1" скомпилить закомментировал строки с "closesocket", WSACleanup и "return 0" и всё работает. а ошибка WSAECONNRESET закономерна, что ж ты хочешь чтоб после посылки на неоткрытый порт (как в твоем примере, когда ПО номер 2 не запущено) у тебя ошибки не было, если она прописана черным по белому в мсдне?
3.3K
11 августа 2006 года
GENA_DJ
123 / / 08.03.2005
[QUOTE=xm...]дальше идет посылка sendto без всяких ошибок[/QUOTE]
Только вот recvfrom() с ошибкой. В этом и вся проблема.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог