2015-02-13 2 views
0

Я пишу программное обеспечение C для взаимодействия с контроллером мотора через UDP. Я использую:C оконная розетка навсегда заблокирована при первом выполнении

  • Win 7 Pro 64-Bit
  • затмение Луна
  • MinGW

На данный момент у меня есть проблема, которая, кажется, гнездо/WSA, связанные с: выполнение моей программы застряло на recvfrom() навсегда (очевидно, что контроллер не отвечает так, как ожидалось). С прилагаемым программным обеспечением это происходит только при первом выполнении (или после того, как оно не выполняется в течение примерно 3 минут), другие программы имели эту проблему 3-4 раза подряд. Взгляд в wirehark показал, что первая (или после 3мин паузы) приводит к передаче пакета «ARP» вместо моего сообщения UDP. Почему это (кажется, ищет место назначения)? Как я могу избежать «срыва» моего программного обеспечения из-за этого?

Неужели я забыл инициализировать что-нибудь?

Мой код выглядит следующим образом:

#include <stdio.h> 
#include <conio.h> 
#include <winsock2.h> 

#define Y_AXIS_IP "XXX.XXX.XXX.XX" 
#define Y_AXIS_PORT 880X 

int startWinsock(void); 

int main() { 
//Start the winsocket (needed to create sockets) 
long ws = startWinsock(); 
if (ws) { 
    printf("ERROR: Failed to init Winsock API! Code: %ld\n", ws); 
    getch(); 
    exit(EXIT_FAILURE); 
} 
//Create an UDP Socket 
SOCKET UDPsocket = socket(AF_INET, SOCK_DGRAM, 0); 
if (UDPsocket == INVALID_SOCKET) { 
    printf("ERROR: Socket could not be created! Code: %d\n", 
      WSAGetLastError()); 
    getch(); 
    exit(EXIT_FAILURE); 
} 
//Create a struct to use with the socket (this gives information about type (AF_INET = Internet Protocol) which port and which IP to use) 
SOCKADDR_IN addrY; 
memset(&addrY, 0, sizeof(addrY)); 
addrY.sin_family = AF_INET; //Assert Type 
addrY.sin_port = htons(Y_AXIS_PORT); //Assert Port 
addrY.sin_addr.S_un.S_addr = inet_addr(Y_AXIS_IP); //assert IP Address 

char message[] = "0000MTX  00000000OR:1:000F\r"; 

int buffersize = 100; 
char *recvbuf = malloc(buffersize); //None of the replys can get larger than 100 chars 

if (recvbuf == NULL) { 
    printf("Out of memory!\n"); 
    getch(); 
    exit(EXIT_FAILURE); 
} 

//clear the receive buffer and prepare the address size 
memset(recvbuf, '\0', buffersize); 
int addrsize = sizeof(addrY); 

//Send the message to the device 
if (sendto(UDPsocket, message, strlen(message), 0, 
     (struct sockaddr *) &addrY, sizeof(addrY)) == SOCKET_ERROR) { 
    printf("sendto() failed with error code : %d", WSAGetLastError()); 
    getch(); 
    exit(EXIT_FAILURE); 
} 

//Receive from device (blocks program until recv event) 
if (recvfrom(UDPsocket, recvbuf, buffersize, 0, (struct sockaddr *) &addrY, 
     &addrsize) == SOCKET_ERROR) { 
    //If not timed out Display the Error 
    printf("recvfrom() failed with error code : %d", WSAGetLastError()); 
    getch(); 
    exit(EXIT_FAILURE); 
} 

printf("%s\n", recvbuf); 
getch(); 

free(recvbuf); 

return 0; 
} 

int startWinsock(void) { 
WSADATA wsa; 
return WSAStartup(MAKEWORD(2, 2), &wsa); 
} 

Я был бы очень счастлив, если бы вы имели какие-либо идеи или предложения. Заранее большое спасибо!

+0

Это полностью звучит как проблема ARP. Читайте о ARP. Вам нужно обработать случай, когда ARP приведет к отказу первого пакета после некоторого времени простоя. – ElderBug

ответ

0

Итак, наконец, я нашел способ справиться с этой проблемой:

1. catch the timeout that occurs at recvfrom 
2. save the sockets address in a temporary socket 
3. close the original socket 
4. end the WSA (call WSACleanup()) 
5. start the WSA (call WSAStartup()) 
6. create a new socket at the address of the former socket 
7. transmit the message again 

, кажется, работает нормально (смотрите также код ниже)

Если вы видите что-то неправильно или опасно с моим кодом, пожалуйста, не стесняйтесь комментировать и помочь моим, чтобы улучшить свои навыки.

Благодарим Вас за помощь и идеи,

Себастьян

Код:

if (recvfrom(*UDPsocket, buffer, buffersize, 0, (struct sockaddr *) &addr, 
     &addrsize) == SOCKET_ERROR) { 

    int WSAerror = WSAGetLastError(); 

    if (WSAerror == 10060) { 

     printf("[WARNING] recvfrom() timed out!\n"); 
     //Store the address of the socket 
     SOCKET *tempsocket = NULL; 
     tempsocket = UDPsocket; 
     //destroy the old socket 
     closesocket(*UDPsocket); 
     WSACleanup(); 
     //create a new socket 
     startWinsock(); 
     *tempsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 

     //Send the message to the device 
     if (sendto(*tempsocket, Frame.pcompletemsg, 
       strlen(Frame.pcompletemsg), 0, (struct sockaddr *) &addr, 
       sizeof(addr)) == SOCKET_ERROR) { 
      printf("[ERROR] sendto() failed with error code : %d\n", 
        WSAGetLastError()); 
      getch(); 
      WSACleanup(); 
      exit(EXIT_FAILURE); 
     } 
     if (recvfrom(*tempsocket, buffer, buffersize, 0, 
       (struct sockaddr *) &addr, &addrsize) == SOCKET_ERROR) { 

      int WSAerror = WSAGetLastError(); 
      printf("[ERROR] recvfrom() failed with error code : %d", 
        WSAerror); 
      getch(); 
      WSACleanup(); 
      exit(EXIT_FAILURE); 
     } 

    } else { 
     printf("[ERROR] recvfrom() failed with error code : %d", WSAerror); 
     getch(); 
     WSACleanup(); 
     exit(EXIT_FAILURE); 
    } 
} 
0
  • Прежде чем компьютер сможет отправить пакет другому хосту, он должен решить свой MAC-адрес. Это делается с помощью запроса ARP. Операционная система обрабатывается прозрачно.

  • recvfrom будет блокировать. Это не ошибка. Есть три основных способа избежать recvfrom от блокировки навсегда, когда нет Incomming данных:

    1. сделать сокет асинхронный, то есть блокирующими
    2. установить тайм-аут (см Set timeout for winsock recvfrom)
    3. использование выбора (Setting winsock select timeout accurately)
+0

ОК, спасибо, я попытался добавить статическую запись в кеш-запись arp, но потом она всегда ** заканчивается таймаутом recv (спасибо за предложение таймаута) это команда, которую я использую для установки статического arp запись: arp -s "destination ip" "destination mac" "source ip" Передача через sendto теперь всегда успешна, но функция recvfrom никогда ничего не получает, есть ли у вас какие-либо дальнейшие идеи, что я мог бы попробовать исправить это? – whargarbel

+0

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

+0

В wirehark кажется, что нет передачи (даже не sendto, хотя sendto() успешно [согласно моей программе]), ни один байт не передается по портам, когда recvfrom заканчивается таймаутом. Таким образом, при каждом первом выполнении sendto как-то не срабатывает, и поэтому recvfrom не может ничего получить. Это проблема с winsocket? – whargarbel

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