#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;
}
Интересная особенность sendto()
Как результат работы 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 сокет нечувствительным к подобного рода ошибкам. Это необходимо для того, чтобы не открывать на машине лишних портов, в то время как отновной порт был все время открыт и доступен.
Как результат работы sendto() может быть ошибка сокета, делающая невозможным дальнейшую работу. WSAGetLastError() возвращает при этом WSAECONNRESET.
На этот счет вопрос: как сделать UDP сокет нечувствительным к подобного рода ошибкам. Это необходимо для того, чтобы не открывать на машине лишних портов, в то время как отновной порт был все время открыт и доступен.[/QUOTE]
А на кой в юдп использовать ассинхроный сокет?????
создай поток слушающий порт с юдп,
и создавай времено сокет для передачи юдп месаги
Я ни слова не говорил, что сокет является асинхронным.
[QUOTE=Romikgy]создай поток слушающий порт с юдп, и создавай времено сокет для передачи юдп месаги[/QUOTE]
Я написал, что не хочу открывать лишних портов. К тому же сам факт возникновения такой ошибки дает дополнительную уязвимость: если ты хочешь закрыть на удаленной машине UDP порт, просто пошли ICMP с "Port Unreachable".
Я написал, что не хочу открывать лишних портов. К тому же сам факт возникновения такой ошибки дает дополнительную уязвимость: если ты хочешь закрыть на удаленной машине UDP порт, просто пошли ICMP с "Port Unreachable".[/QUOTE]
да насчет асинхроного ступил ,звыняюсь :)
А о каком лишнем порту речь?
и насчет ICMP не совсем догнал :(
А о каком лишнем порту речь?
[/QUOTE]
Ты же сам говоришь:
[QUOTE=Romikgy]
создавай времено сокет для передачи юдп месаги
[/QUOTE]
[QUOTE=Romikgy]
и насчет ICMP не совсем догнал :(
[/QUOTE]
Если при попытке отправить UDP - пакет я получаю ICMP - пакет об отказе, это значит, что отправляющий сокет становится недоступным для дальнейшей работы.
Переформулирую вопрос. Как сделать "всегда живой" UDP сокет, по которому я могу как передавать, так и принимать пакеты независимо от того, может ли адресат их принять или нет?
UDP-сокет всегда живой. ECONNRESET может выдаваться только для TCP-сокета, т. к. только для него существует понятие соединения. UDP-сокет просто тупо плюется пакетами и все, ему пофиг принял их кто-нибудь или нет, он даже об этом не знает.
Приведи исходник , а то действительно получается что ты юзаешь TCP пакет а не UDP
ПО №1
Код:
ПО №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;
}
#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 имеет проблему совместимости, а также требует административных привилегий учетной записи для запуска ПО.
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. насколько я понял сокет у тя блокирующий, а ты его в основном потоке крутишь, висяк проги имхо обеспечен
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]
"Висяк" то в данном примере мне и нужен. Если порт назначения открыт, то все пучком. Но если получатель недоступен, то после посылки сокет "умирает" при попытках на нём данные принять.
Статья: Q263823 WinSock Recvfrom() Now Returns WSAECONNRESET Instead of Blocking or Timing Out.
Решение: Установка hotfix'a. И ваще, если у тебя 2000, то нафиг его, переходи на XP =) Там таких траблов у меня не было.
тогда чего заморачиваешься с юдп делай на тсп, плюс надежность возврастет
2003 SERVER EE
[QUOTE=Romikgy]
делай на тсп
[/QUOTE]
не хотел бы ... из соображений скорострельности как минимум. Теперь уже задумался.
Вопрос причины остался нерешенным. Буду искать.
не закрывай сокет после ошибки вот и всё, зачем его закрывать? это же удп. дальше идет посылка sendto без всяких ошибок: только что сам попробовал твой код "ПО №1" скомпилить закомментировал строки с "closesocket", WSACleanup и "return 0" и всё работает. а ошибка WSAECONNRESET закономерна, что ж ты хочешь чтоб после посылки на неоткрытый порт (как в твоем примере, когда ПО номер 2 не запущено) у тебя ошибки не было, если она прописана черным по белому в мсдне?
Только вот recvfrom() с ошибкой. В этом и вся проблема.