2

编辑:向下滚动以查看更新的代码。

我想用 C 语言为 Minecraft 构建一个假播放器。

我的 Minecraft 服务器 (bukkit) 在我的本地 IP 192.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

也许这是因为 char-set ?有人知道为什么吗?这是我的代码:

#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 (或您最喜欢的宽字符数据类型)指定如下。并在文字上使用 anL来指定一个宽字符串。以字节为单位的实际发送长度需要确保将字符串长度乘以 2。

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

然后,同样地,使用宽字符串函数来复制字符串(strcat 不起作用)。

要将字符串长度放在 0x02 协议代码之后的两个字节中,您可以这样做:

*((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] );

然后提取字符串(协议字节后面的两个字节应该是连接哈希字符串的长度(按网络字节顺序)。所以你需要使用ntohs它来提取它。然后下面的N个宽字符将代表哈希.

写完所有这些,在我看来,您可能想要寻找一个库来处理所有协议。我没有看过,但似乎有一些与 Minecraft 相关的 C 套接字库可用。只是一个疯狂的猜测。 编辑再三考虑,这取决于您的目标。如果您只是想尽快构建客户端,那么寻找库绝对是有意义的。但是,如果您想了解协议、网络编程等的详细信息,那么在您开始的级别编写它是一个好主意,并且会很有趣,因为您可以逐步进行显示真实结果的步骤经常。

另一件事。memset分配内存后可能没有达到您的预期。假设是 32 位架构,则为sizeof( packet )4(它是一个 4 字节指针)。但是,由于您将使用数据填充数据包,因此 memset 并不是必需的。

于 2012-06-28T23:59:59.543 回答