编辑:向下滚动以查看更新后的代码。
我想用C语言为Minecraft打造一个假玩家。
My Minecraft服务器(bukkit)正在侦听端口25565,在我的本地IP 192.168.1.141上
当我启动我的应用程序时,(当它通过套接字发送数据时)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.
谢谢大家!
答案 0 :(得分:2)
一般来说,你所做的似乎是正确的。我想,当您的测试代码关闭自己的套接字时,服务器发生“连接丢失”消息。但是,您似乎没有正确处理string data type。该字符串需要以Unicode格式发送,并且您似乎将其作为单字节字符发送。此外,字符串需要以表示为2字节整数的长度开头。
也可以使用wchar_t(或您喜欢的宽字符数据类型)将握手字符串指定如下。并在文字上使用L
来指定宽字符串。实际的发送长度(以字节为单位)需要确保将字符串长度乘以2.
wchar_t pseudo [] = 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个宽字符代表哈希值。
编写完所有内容后,在我看来,您可能希望寻找一个库来处理所有协议。我没看过,但似乎有一些可用于C的Minecraft相关套接字库。只是一个疯狂的猜测。 修改第二个想法,这取决于您的目标。如果您只是想尽快建立一个客户端,那么寻找一个库肯定是有意义的。但是,如果您想要了解协议,网络编程等的详细信息,那么在您开始的级别编写它是一个好主意,并且会很有趣,因为您可以制作显示实际结果的增量步骤经常。
另一件事。分配内存后memset
可能没有按预期执行。假设一个32位架构,sizeof( packet )
将为4(它是一个4字节指针)。但是,由于您将使用数据填充数据包,因此不需要memset。