2

編集:下にスクロールして、更新されたコードを確認します。

Minecraft用の偽のプレーヤーをC言語で作成したいと思います。

Minecraftサーバー(bukkit)は、ローカルIP192.168.1.141のポート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;
}

よろしくお願いします、そして私の悪い英語を許してください:)

アップデート :

建設的なコメントのおかげで、今ではすべてが完璧に機能しています。これが私の古いコードで何が起こっていたかを確認するための作業コードです。

#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.

みなさん、ありがとうございました!

4

1 に答える 1

2

一般的に、あなたがしていることは正しいように見えます。サーバーからの「接続が失われました」というメッセージは、テストコードが独自のソケットを閉じるときに発生すると思います。ただし、文字列データ型を正しく処理していないようです。文字列はUnicodeとして送信する必要があり、シングルバイト文字として送信しているように見えます。また、文字列の前に2バイト整数で表される長さを付ける必要があります。

代わりに、ハンドシェイク文字列をwchar_t(またはお気に入りのワイド文字データ型)で次のように指定する必要があります。また、リテラルでonを使用しLて、幅の広い文字列を指定します。バイト単位の実際の送信長は、文字列の長さに2を掛ける必要があります。

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

次に、同様に、ワイド文字列関数を使用して文字列をコピーします(strcatは機能しません)。

0x02プロトコルコードの後の2バイトに文字列の長さを入れるには、次のようにします。

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

文字列をパケットにコピーするには、おそらくこれです(コンパイルせずにオンザフライでこれを書いています:

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

バイト単位の実際の送信長は次のようになります。 3 + pseudoLen * sizeof( wchar_t )

結果の応答を印刷するときは、次のようなものが必要になる場合があります。

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

次に、文字列を抽出します(プロトコルバイトに続く2バイトは、接続ハッシュ文字列の長さ(ネットワークバイト順)である必要があります)。したがって、を使用ntohsして抽出する必要があります。次に、次のN個のワイド文字がハッシュを表します。 。

それをすべて書いたので、すべてのプロトコルを処理するライブラリを探したいと思うかもしれません。私は調べていませんが、C用のMinecraft関連のソケットライブラリが利用できるようです。ただの大げさな推測。 編集考え直して、それはあなたの目標に依存します。できるだけ速くクライアントを構築したいだけなら、ライブラリを探すのは間違いなく理にかなっています。ただし、プロトコルやネットワークプログラミングなどの詳細を知りたい場合は、最初のレベルでそれを書くことをお勧めします。実際の結果を示す段階的な手順を実行できるため、非常に楽しいでしょう。かなり頻繁に。

もう1つ。メモリを割り当てたmemset後は、期待どおりに動作しない可能性があります。32ビットアーキテクチャを想定すると、は4にsizeof( packet )なります(4バイトのポインタです)。ただし、パケットにデータを入力するため、memsetは実際には必要ありません。

于 2012-06-28T23:59:59.543 に答える