0

我正在尝试用 C++ 编写一个 irc 机器人,并负责连接和设置我的昵称以及身份,ping 也可以正常工作。我遇到的唯一问题是加入频道。服务器不断发回“JOIN :unknown command”我相信以下几行是最相关的:

#define JOIN "JOIN #test\r\n"
send(IrcSocket, JOIN, strlen(JOIN),0);

如果我所包含的入门程序无法解决任何问题,这可能有点令人眼花缭乱。

#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <string>
#pragma comment(lib, "Ws2_32.lib")

int main()
{
    WSADATA wsaData;
    int iresult=WSAStartup(MAKEWORD(2,2),&wsaData);
    if(iresult!=0)
    {
                  printf("WSAStartup Failed: %d \n", iresult);
                  return 1;
    }
    struct addrinfo *result=NULL, *ptr=NULL, hints;
    ZeroMemory(&hints,sizeof(hints));
    hints.ai_family=AF_INET;
    hints.ai_socktype=SOCK_STREAM;
    hints.ai_protocol=IPPROTO_TCP;
    #define DEFAULT_PORT "6667"
    #define DEFAULT_IP "192.168.0.10"
    iresult = getaddrinfo(DEFAULT_IP,DEFAULT_PORT,&hints,&result);
    if(iresult!=0)
    {
                  printf("getaddrinfo failed: %d\n", iresult);
                  WSACleanup();
                  return 1;
    }
    SOCKET IrcSocket= INVALID_SOCKET;
    ptr=result;
    IrcSocket=socket(ptr->ai_family, ptr->ai_socktype,ptr->ai_protocol);
    if (IrcSocket == INVALID_SOCKET)
    {
       printf("Error at socket(): %d \n", WSAGetLastError());
       freeaddrinfo(result);
       WSACleanup();
       return 1;
    }
    iresult=connect(IrcSocket,ptr->ai_addr,ptr->ai_addrlen);
    if(iresult==SOCKET_ERROR)
    {
       closesocket(IrcSocket);
       IrcSocket=INVALID_SOCKET;
       freeaddrinfo(result);
    }


    if(IrcSocket == INVALID_SOCKET)
    {
       printf("Unable to connect to irc server!");
       WSACleanup();
       return 1;
    }
    std::cout<<("connection made\n");
    #define NICK "NICK bottester\r\n"
    #define IDENT "USER bottester 0 0 bottester\r\n"
    #define JOIN "JOIN #test\r\n"
    char stringbuffer[256];

    iresult=send(IrcSocket,NICK, strlen(NICK),0);
     if(iresult == SOCKET_ERROR)
    {
       printf("send failed: %d\n", WSAGetLastError());
       closesocket(IrcSocket);
       WSACleanup();
       std::cin.get();
       return 1;
    }
    iresult=send(IrcSocket, IDENT, strlen(IDENT),0);
    if(iresult == SOCKET_ERROR)
    {
       printf("send failed: %d\n", WSAGetLastError());
       closesocket(IrcSocket);
       WSACleanup();
       std::cin.get();
       return 1;
    }
    std::cout<<"entering ping loop\n";
    char pingnumber[128];
    char pinganswer[17]="PONG :";
    #define PRMSG "PRIVMSG test :TESTBOT IS HERE!\r\n"
    for(;;)
    {
           memset(stringbuffer,0,256);
           recv(IrcSocket,stringbuffer,sizeof(stringbuffer),0);
           for(int j=0;j<strlen(stringbuffer);j++)
           {
                   std::cout<<j<<stringbuffer[j]<<"\n";
           if(stringbuffer[j]=='P' && stringbuffer[j+1]=='I' && stringbuffer[j+2]=='N' && stringbuffer[j+3]=='G')
           {
           memset(pingnumber,0,10);
           std::memcpy(pingnumber, stringbuffer+j+6,10);
           std::memcpy(pinganswer+6,pingnumber,10);
           std::memcpy(pinganswer+16, "\r\n",strlen("\r\n"));
           send(IrcSocket,pinganswer,strlen(pinganswer),0);
           std::cout<< "PINGED<"<<pingnumber<<"\n";
           iresult=send(IrcSocket, JOIN, strlen(JOIN),0);
           std::cout<< "JOINED\n";
           send(IrcSocket, PRMSG, strlen(PRMSG),0);
           }
           }
    }


}
4

1 回答 1

0

在发送 JOIN 之前,您无需等待注册完成。

你的客户太简单了,真的。为了获得您想要的效果,您可以在 USER/NICK 命令和 JOIN 命令之间设置一个睡眠。

正确的非 kludgy 解决方案是使用 poll、select 等进行正确的发送/接收轮询循环,等待 001 数字(您在注册连接后收到的第一个正确的数字)或更正确的是 RPL_ENDOFMOTD (376) 或ERR_NOMOTD (422)。收到此行后,发送您的 JOIN。

见:https ://www.rfc-editor.org/rfc/rfc1459

另请参阅:https ://msdn.microsoft.com/en-us/library/windows/desktop/ms740141%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

此外,您确实需要响应更多内容,而不是 PING 才能创建一个正常运行的客户端,但这是另一天的事情。一些服务器在注册期间发送一个“安全”PING,您必须在服务器接受连接并发送 001 数字之前做出响应。如果您不对此做出响应,您的连接将永远不会注册并最终 ping 超时。

于 2016-10-18T07:34:29.390 回答