2012-06-28 2 views
2

편집 : 아래로 스크롤하여 업데이트 된 코드를 확인하십시오.소켓의 연결이 끊어집니다.

나는 C 언어로 Minecraft를위한 가짜 플레이어를 만들고 싶습니다.

내 로컬 IP 192.168.1.141에 (bukkit)가 포트 25565에서 수신 대기

내 마인 크래프트 서버는

내 응용 프로그램을 실행

(가 보낼 때 데이터가 소켓 물마루)를 bukkit 서버는 말한다 "192.168 .1.141 : xxxxx는 "연결을 잃고,

내 응용 프로그램 말해 :

socked created 
socked connected 
to send data = (smilie)kekos91;192.168.1.141:25565 
to send length = 27 
send ! 
response data = (a strange symbol) 
response length = 1 
socket disconnected 

어쩌면이 때문에 숯불 설정이다? 누군가가 이유를 알고 있습니까? 여기에 내 코드 : 사전에

#include <stdio.h> 
#include <stdlib.h> 
#include <windows.h> 
#include <winsock2.h> 

int main() 
{ 
    char pseudo[] = "kekos91;192.168.1.141:25565"; 
    int pseudoLen = strlen(pseudo); 

    char *packet = NULL; 
    packet = (char*)malloc(3 + ((pseudoLen)*sizeof(char)*2)); 
    if(packet == NULL) 
    { 
     return -1; 
    } 
    memset(packet, '\0', sizeof(packet)); 
    packet[0] = (char)0x02; 
    strcat(packet, pseudo); 
    int pLenght = strlen(packet); 

    char handshake[200]; 

    HANDLE hConsole; 
    WSADATA wsaData; 
    int iResult = 0; 

    SOCKET serverSocket; 
    sockaddr_in serverInfos; 

    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 
    if (iResult != NO_ERROR) { 
     printf("WSAStartup() failed with error: %d\n", iResult); 
     return -1; 
    } 

    serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (serverSocket == INVALID_SOCKET) { 
     printf("socket function failed with error: %i\n", WSAGetLastError()); 
     WSACleanup(); 
     return -1; 
    } 
    printf("socket created\n"); 

    serverInfos.sin_family = AF_INET; 
    serverInfos.sin_addr.s_addr = inet_addr("192.168.1.141"); 
    serverInfos.sin_port = htons(25565); 

    iResult = connect(serverSocket, (SOCKADDR *)&serverInfos, sizeof(serverInfos)); 
    if (iResult == SOCKET_ERROR) 
    { 
     printf("connect function failed with error: %i\n", WSAGetLastError()); 
     iResult = closesocket(serverSocket); 
     if (iResult == SOCKET_ERROR) 
     { 
      printf("closesocket function failed with error: %i\n", WSAGetLastError()); 
     } 
     WSACleanup(); 
     return -1; 
    } 
    printf("socket connected\n"); 



    printf("to send data = %s\n", packet); 
    printf("to send length = %i\n", pseudoLen); 
    Sleep(500); // after this point, the connection is loose :(
    if(send(serverSocket, (char*)packet , pLenght, 0) == SOCKET_ERROR) 
    { 
     printf("send function failed with error: %i\n", WSAGetLastError()); 
     iResult = closesocket(serverSocket); 
     if (iResult == SOCKET_ERROR) 
     { 
      printf("closesocket function failed with error: %i\n", WSAGetLastError()); 
     } 
     WSACleanup(); 
     return -1; 
    } 
    free(packet); 

    printf("send !\n"); 




    if(recv(serverSocket, (char*)&handshake, 200, 0) == SOCKET_ERROR) 
    { 
     printf("recv function failed with error: %i\n", WSAGetLastError()); 
     iResult = closesocket(serverSocket); 
     if (iResult == SOCKET_ERROR) 
     { 
      printf("closesocket function failed with error: %i\n", WSAGetLastError()); 
     } 
     WSACleanup(); 
     return -1; 
    } 

    printf("response data = %s\n", handshake);  
    printf("response length = %i\n", strlen(handshake)); 

    iResult = closesocket(serverSocket); 
    if (iResult == SOCKET_ERROR) { 
     printf("closesocket function failed with error %i\n", WSAGetLastError()); 
     WSACleanup(); 
     return -1; 
    } 
    printf("socket disconnected.\n"); 

    WSACleanup(); 
    Sleep(5000); 
    return 0; 
} 

덕분에, 내 나쁜 영어 실례 :

UPDATE : 건설적인 의견에

덕분에, 모든 것이 이제 완벽하게 작동합니다. 다음은 이전 코드에서 어떤 작업이 수행되었는지 확인할 수있는 작업 코드입니다.

지금
#include <stdio.h> 
#include <stdlib.h> 
#include <windows.h> 
#include <winsock2.h> 

int main() 
{ 
    int iSocketResult = 0; // it will retrieve sockets return functions, like send/recv/errors 

    wchar_t wcPseudo[] = L"kekos91;192.168.1.141:25565"; 
    int iPseudoLen = wcslen(wcPseudo); 

    char *pPacket = NULL; 
    pPacket = (char*)malloc(3 + ((iPseudoLen)*sizeof(char)*2)); 
    if(pPacket == NULL) 
    { 
     return -1; 
    } 
    pPacket[0] = 0x02; 


    *(short*)(pPacket + 1) = htons(iPseudoLen); 
    memcpy(pPacket + 3, wcPseudo, iPseudoLen * sizeof(wchar_t)); 

    int iPacketLen = 3 + iPseudoLen*sizeof(wchar_t) ;  

    char *handshake = NULL; 
    handshake = (char*)malloc(sizeof(char)*200); 
    if(handshake == NULL) 
    { 
     return -1; 
    } 


    HANDLE hConsole; 
    WSADATA wsaData;   

    SOCKET serverSocket; 
    sockaddr_in serverInfos; 

    iSocketResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 
    if (iSocketResult != NO_ERROR) { 
     printf("WSAStartup() failed with error: %d\n", iSocketResult); 
     return -1; 
    } 

    serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (serverSocket == INVALID_SOCKET) { 
     printf("socket function failed with error: %i\n", WSAGetLastError()); 
     WSACleanup(); 
     return -1; 
    } 

    printf("socket created\n"); 

    serverInfos.sin_family = AF_INET; 
    serverInfos.sin_addr.s_addr = inet_addr("192.168.1.141"); 
    serverInfos.sin_port = htons(25565); 

    iSocketResult = connect(serverSocket, (SOCKADDR *)&serverInfos, sizeof(serverInfos)); 
    if (iSocketResult == SOCKET_ERROR) 
    { 
     printf("connect function failed with error: %i\n", WSAGetLastError()); 
     iSocketResult = closesocket(serverSocket); 
     if (iSocketResult == SOCKET_ERROR) 
     { 
      printf("closesocket function failed with error: %i\n", WSAGetLastError()); 
     } 
     WSACleanup(); 
     return -1; 
    } 
    printf("socket connected\n\n"); 

    printf("to send protocol = %#1.2x \nlenght = %i\n", pPacket[0], iPseudoLen); 

    iSocketResult = send(serverSocket, pPacket , iPacketLen, 0); 
    if(iSocketResult == SOCKET_ERROR) 
    { 
     printf("send function failed with error: %i\n", WSAGetLastError()); 
     iSocketResult = closesocket(serverSocket); 
     if (iSocketResult == SOCKET_ERROR) 
     { 
      printf("closesocket function failed with error: %i\n", WSAGetLastError()); 
     } 
     WSACleanup(); 
     return -1; 
    } 
    free(pPacket); 

    printf("send %i (bytes) !\n\n",iSocketResult); 


    iSocketResult = recv(serverSocket, handshake, 50, 0); 
    if(iSocketResult == SOCKET_ERROR) 
    { 
     printf("recv function failed with error: %i\n", WSAGetLastError()); 
     iSocketResult = closesocket(serverSocket); 
     if (iSocketResult == SOCKET_ERROR) 
     { 
      printf("closesocket function failed with error: %i\n", WSAGetLastError()); 
     } 
     WSACleanup(); 
     return -1; 
    } 

    printf("response protocol = %#1.2x\nresponse lenght = %i (bytes)\n\n", handshake[0], iSocketResult); 
    free(handshake);  


    iSocketResult = closesocket(serverSocket); 
    if (iSocketResult == SOCKET_ERROR) 
    { 
     printf("closesocket function failed with error %i\n", WSAGetLastError()); 
     WSACleanup(); 
     return -1; 
    } 
    printf("socket disconnected.\n"); 

    WSACleanup(); 
    Sleep(7000); 
    return 0; 
} 

출력 콘솔은 인쇄 : 당신이 모든

socket created 
socket connected 

to send protocol = 0x02 
lenght = 27 
send 57 (bytes) ! 

response protocol = 0x02 
response lenght = 37 (bytes) 

socket disconnected. 

감사합니다!

+0

이 데이터에서 문자열 처리 루틴을 사용하면주의해야합니다. 나는 즉시 잘못된 점을 발견하지 못했지만 첫 번째 바이트가'0x02' 일 때 응답이 잘 출력되지 않을 수 있습니다. – sarnold

+0

나는 이해하지만, http://wiki.vg/Protocol#Handshake_.280x02.29에 응답하는 것은 동일한 바이트 인 0x02로 시작해야하지만 같은 방식으로 인쇄되지는 않습니다! – kekos91

+0

wireshark를 사용하여 전선에 무엇이 있는지 알고 계십니까? 그러면 실제 진행 상황을보다 쉽게 ​​확인할 수 있습니다. – sarnold

답변

2

일반적으로 옳은 것처럼 보입니다. 테스트 코드가 자체 소켓을 닫을 때 서버에서 "연결이 끊어진"메시지가 발생한다고 생각합니다. 그러나 string data type을 올바르게 처리하지 않은 것 같습니다. 문자열을 유니 코드로 보내야하며,이를 1 바이트 문자로 보내고있는 것처럼 보입니다. 또한 문자열은 2 바이트 정수로 표현 된 길이 앞에 와야합니다.

대신 핸드 쉐이크 문자열을 wchar_t (또는 원하는 와이드 문자 데이터 유형)와 함께 다음과 같이 지정해야합니다. 리터럴에 L을 사용하여 넓은 문자열을 지정하십시오. 바이트 단위의 실제 전송 길이는 문자열 길이에 2를 곱해야합니다.

wchar_t 의사 [] = L "kekos91; 192.168.1.141 : 25565"; int pseudoLen = wcslen (의사);

그런 다음 와이드 문자열 함수를 사용하여 문자열을 복사하십시오 (strcat가 작동하지 않음).

는 0x02의 프로토콜 코드 뒤에 2 바이트의 문자열 길이를 넣으려면,이 작업을 수행 할 수 있습니다

*((short*)(packet + 1) = htons(pseudolLen); 

는 패킷으로 문자열을 복사하려면, 어쩌면이 (나는 즉시이 쓰고 있어요 컴파일하지 않고 :

memcpy(packet + 3, pseudo, pseudoLen * sizeof(wchar_t)); 

바이트의 실제 전송 길이는 다음과 같습니다 3 + pseudoLen * sizeof(wchar_t)

결과 응답을 인쇄, 이런 일이 될 일을 Y OU 원하는 :

printf("Protocol response: %02x\n", handshake[0]); 

그리고 문자열을 (프로토콜 바이트를 다음과 같은 2 바이트가 네트워크 바이트 순서로 연결 해시 문자열의 길이 (해야한다) 압축을 풉니 다. 따라서 추출하려면 ntohs을 사용해야합니다. 그리고 나서 다음 N 개의 넓은 문자가 해시를 나타냅니다.

모든 것을 작성 했으므로 모든 프로토콜을 처리하기 위해 라이브러리를 찾고 싶을 것 같습니다. 나는 보지 못했지만 C가 사용 가능한 Minecraft 관련 소켓 라이브러리가있는 것 같습니다. 단지 야생의 추측. 두 번째 생각에, 그것은 당신의 목표에 달려 있습니다. 가능한 한 빨리 클라이언트를 빌드하고 싶다면 라이브러리를 찾는 것이 좋습니다. 그러나 프로토콜, 네트워크 프로그래밍 등의 세부 정보를 배우고 싶다면 시작한 레벨로 작성하는 것이 좋습니다. 실제 결과를 보여줄 수있는 점진적인 단계를 수행 할 수 있으므로 많은 재미가 있습니다. 꽤 자주.

다른 하나. 메모리를 할당 한 후 memset은 예상 한대로 수행하지 않을 수 있습니다. 32 비트 아키텍처를 가정하면 sizeof(packet)은 4 (4 바이트 포인터)가됩니다. 그러나 패킷으로 데이터를 채울 것이므로 memset은 실제로 필요하지 않습니다.

+0

와우,이 정확한 답변을 주셔서 감사합니다, 나는 내일 시험해 보겠습니다. 고마워요! – kekos91

+0

@ kekos91 : 어떻게 작동되는지 알려주세요. 나는 막 집을 떠나기 직전에 질문을보고 너를 보았다. 나는 minecraft 프로토콜을 본 적이 없지만 꽤 직관적 인 것처럼 보입니다. 내 대답은 그것을 정의하는 위키를 보는 것에 순전히 기반합니다. 나는이 게임에 많은 시간을 낭비하는 딸이 있기 때문에 그것에 대해 궁금했습니다. –

+0

물론 알려 드리겠습니다. 나는 내일 노력할 것이고, 작동하는 코드로 주제를 업데이트 할 것이다 (만약 작동한다면)! – kekos91