2010-07-28 1 views
4

아마 지금까지 만난 가장 이상한 버그 일 것입니다.Winsock의 connect()는 WSAETIMEDOUT을 영구적으로 반환하지만 PuTTY는 동일한 포트에 연결합니다.

Windows XP Embedded에서 실행되는 타사 응용 프로그램에 연결해야합니다. 네트워크 연결 현재 및 작동 : Windows XP SP3에서 실행중인 PuTTY를 사용하여 예상 포트에 연결하고 일부 텔넷과 같은 작업을 수행 할 수 있습니다. 자, 내 응용 프로그램은 매우 간단한 C (VC++ 2008) 프로그램은 다음과 같습니다

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    WSADATA wsaData = { 0 }; 
    if (SOCKET_ERROR == WSAStartup(MAKEWORD(2, 0), &wsaData)) 
     return Error("Failed to initialize sockets."); 

    SOCKET client = INVALID_SOCKET; 

    const char *pserver = "172.22.1.3"; 

    client = socket(AF_INET, SOCK_STREAM, 0); 

    if (INVALID_SOCKET != client) 
    { 
     sockaddr_in s = { 0 }; 
     s.sin_family = AF_INET; 
     s.sin_port = htons(4799); 
     hostent *e = gethostbyname(pserver); 
     memmove(&s.sin_addr, e->h_addr, e->h_length); 

     std::cout << "Connecting to: " << pserver << std::endl; 

     if (SOCKET_ERROR != connect(client, (sockaddr*)&s, sizeof(s))) 
     { 
      std::cout << "Successfully connected." << std::endl; 
     } 
     else 
      std::cout << "Can't connect: " << WSAGetLastError() << std::endl; 
    } 

    getchar(); 

    if (INVALID_SOCKET != client) 
     closesocket(client); 

    return 0; 
} 

내가 컴파일하고 내가 WSAETIMEDOUT 오류를 받고 있어요이 프로그램을 실행할 때마다. 의아해하면서, 나는 더 깊게 파고 들어가서 수신기 쪽에서 두 개의 Wireshark 덤프를 만들었다. 하나는 PuTTY를, 다른 하나는 내 애플리케이션으로, 같은 PC에서 실행되어 동일한 장비 (첫 번째 SYN 패킷)에 연결되었다.

퍼티 :

No.  Time  Source    Destination   Protocol Info 
     1 0.000000 172.22.1.61   172.22.1.3   TCP  atc-lm > 4799 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 WS=0 TSV=0 TSER=0 

Frame 1 (78 bytes on wire, 78 bytes captured) 
Ethernet II, Src: Dell_b8:4a:31 (00:26:b9:b8:4a:31), Dst: EEPD_96:04:48 (00:e0:33:96:04:48) 
Internet Protocol, Src: 172.22.1.61 (172.22.1.61), Dst: 172.22.1.3 (172.22.1.3) 
Transmission Control Protocol, Src Port: atc-lm (1170), Dst Port: 4799 (4799), Seq: 0, Len: 0 

0000 00 e0 33 96 04 48 00 26 b9 b8 4a 31 08 00 45 00 ..3..H.&..J1..E. 
0010 00 40 04 a1 40 00 80 06 9b aa ac 16 01 3d ac 16 [email protected]@........=.. 
0020 01 03 04 92 12 bf 9a 99 fc ec 00 00 00 00 b0 02 ................ 
0030 ff ff 2c bd 00 00 02 04 05 b4 01 03 03 00 01 01 ..,............. 
0040 08 0a 00 00 00 00 00 00 00 00 01 01 04 02   .............. 

내 응용 프로그램 :

No.  Time  Source    Destination   Protocol Info 
     1 0.000000 Dell_b8:4a:31   EEPD_96:04:48   FC  [Malformed Packet] 

Frame 1 (78 bytes on wire, 78 bytes captured) 
Ethernet II, Src: Dell_b8:4a:31 (00:26:b9:b8:4a:31), Dst: EEPD_96:04:48 (00:e0:33:96:04:48) 
MDS Header(Unknown(0)/Unknown(0)) 
[Malformed Packet: FC] 

0000 00 e0 33 96 04 48 00 26 b9 b8 4a 31 00 00 00 00 ..3..H.&..J1.... 
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
0020 00 00 00 00 00 00 00 00 6d 8b 00 00 00 00 b0 02 ........m....... 
0030 ff ff 90 73 00 00 02 04 05 b4 01 03 03 00 01 01 ...s............ 
0040 08 0a 00 00 00 00 00 00 00 00 01 01 04 02   .............. 

기본적으로, 전체 IP 페이로드 대신 유효한 바이트 × 00로 닦아되고있다.

이제 가장 이상한 부분이 있습니다. 나는 .NET 3.5 유사한 프로그램을 작성 :

static void Main(string[] args) 
{ 
    var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Unspecified); 
    socket.Connect("172.22.1.3", 4799); 

    Console.WriteLine("Connected"); 

    Console.ReadLine(); 
    socket.Disconnect(true); 
} 

동일한 Windows XP SP3 PC, 동일한 네트워크 연결 - 내 .NET 응용 프로그램은 단순히 원격 응용 프로그램에 연결! 또한, 내 원래의 C 응용 프로그램은 Windows 7 x64에서 다른 랩톱에서 정상적으로 작동합니다. 하루 종일 헤드 밴드를 사용하면 C 응용 프로그램이 원격 클라이언트에 연결되지 않는 두 개의 Windows XP SP3 랩톱과 C 응용 프로그램이 문제없이 작동하는 Windows XP SP3 및 Windows 7 x64 랩톱이 각각 하나씩 있습니다.

첫 번째 추측은 네트워크 드라이버 였지만 PuTTY 및 .NET 응용 프로그램은 동일한 랩톱에서 작동합니다!

다른 누구도 exerienced 뭔가 내게 조언을 해줄 수 있었습니까?

감사합니다.

답변

0

IP 주소에 연결하고 있으므로 gethostbyname()을 사용하지 마십시오 (특히 오류 응답을 확인하지 않기 때문에). 대신 inet_addr()을 사용하십시오 :

sockaddr_in s = { 0 }; 
s.sin_family = AF_INET; 
s.sin_port = htons(4799); 
s.sin_addr.s_addr = inet_addr(pserver); // <-- here 
+0

불행히도, 그 중 하나가 작동하지 않았다. 뿐만 아니라 getaddrinfo(). – wasker

+0

점으로 구분 된 쿼드 변환은 gethostbyname()의 알려진 지원 기능입니다. 점으로 구분 된 쿼드 (quad)가 있음을 알 때 inet_addr()을 호출하는 것이 더 효율적입니다. –

+0

잘못된 포인터 또는 바이트 길이를 사용하여 메모리가 손상되는 경우를 대비하여 memmove()에 대한 호출을 제거하려고했습니다. –

0

나는 어떤 비슷한 문제가있었습니다. WSAETIMEDOUT 대신 WSAEADDRINUSE를 반환했습니다. setsockopt()는 그 문제를 해결했습니다.

또한 소켓 (..., IPPROTO_TCP)을 사용하여 socket (..., 0) 호출을 업데이트하는 것이 좋습니다.

0

첫 번째 - API의 기본값을 신뢰하지 마십시오. TCP를 프로토콜로 강제 설정하고 실제로 필요한 소켓 옵션을 설정해야합니다. 서로 다른 코드와 버전의 업데이트가 적용될 수 있도록 모든 코드를 정적으로 연결하지는 않습니다. 모든 옵션과 기본값을 강요하면 무수히 많은 QFE의 부작용과 문서화되지 않은 부작용을 줄이는 데 도움이됩니다.

두 번째 - 당신은 {x86, x64}을 (를) 만들고있는 것처럼 보입니다. x86 및 x64 빌드 사이에 가능한 차이점을 확인하십시오. 절대적으로 양쪽을 청소해야합니다. 즉, 명시 적으로 모든 것을 삭제한다는 의미입니다. 따라서 다중 플랫폼을 빌드 할 때 혼합 빌드가 항상 발생할 수 있습니다.

3 위 - Wireshark는 실제로 앱에서 트래픽을 감지합니까, 아니면 네트워크 노이즈일까요? 내가 물어 보는 이유는 실제 트래픽이 없다면 그룹 정책이나 방화벽 일 수 있다는 것입니다. PUTTY는 내장 된 방화벽에서 포트를 열기 위해 명시 적으로 API 호출을 수행합니다.

이 시점에서 내 아이디어가 고갈됩니다. 아, 시도해 볼 x64 XP가 있습니까? 그냥 호기심.

0

socket 호출에서 IPPROTO_TCP을 명시 적으로 명시하면 API를 선택하지 마십시오. 당신이 그것을 시도 할 때까지는 다른 것을 볼만한 가치가 없습니다.

1

이 잘 나에게 보이지 않는 :

memmove(&s.sin_addr, e->h_addr, e->h_length); 
        ^^^^^^^^^-- here 

는 VC의 문서에 액세스 할 수없는, 그러나 &e->h_addr이어야한다?

그냥 w.A.G. 버전의 IP 블록이 제로화되어 있기 때문에, memmove가 잘못된 지점에서 읽고, 사용되지 않은 메모리 블록을 복사하고있는 이유를 나타냅니다.

+0

memcpy가 아니라 memcpy 여야합니다. – grieve

관련 문제