c ++在irc bot的recv函数中处理多个字符串

时间:2016-02-16 16:34:27

标签: c++ string irc recv

我正在尝试用c ++编写一个简单的irc机器人(我以前在python中做过这个,但是我正在努力处理使用c ++特别是unicode字符串的字符串。)

到目前为止,我可以连接到IRC服务器并读取缓冲区,但缓冲区可以包含多行,并且它还包含大量空数据。还有一种可能是宽字符或单个消息行溢出缓冲区。

我想读取缓冲区,然后逐行处理每个'\ n'终止行的字符串。

#include "stdafx.h"
#include <stdio.h>
#include <string>
#include <iostream>

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char \
*pass = "pass",
*bot_owner = "name",
*nick = "name",
*serv = "irc.twitch.tv",
*chan = "#name";

using namespace std;


int main()
{

            int ret;
            char buf[512] = "";
#ifdef _WIN32
            SOCKET sock;
            struct WSAData* wd = (struct WSAData*)malloc(sizeof(struct WSAData));
            ret = WSAStartup(MAKEWORD(2, 0), wd);
            free(wd);
            if (ret) { puts("Error loading Windows Socket API"); return 1; }
#else
            int sock;
#endif
            struct addrinfo hints, *ai;
            memset(&hints, 0, sizeof(struct addrinfo));
            hints.ai_family = AF_UNSPEC;
            hints.ai_socktype = SOCK_STREAM;
            hints.ai_protocol = IPPROTO_TCP;
            if (ret = getaddrinfo(serv, "6667", &hints, &ai)) {
                //puts(gai_strerror(ret)); // this doesn't compile
                return 1;
            }
            sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
            if (ret = connect(sock, ai->ai_addr, ai->ai_addrlen)) {
                //puts(gai_strerror(ret)); // this doens't compile
                return 1;
            }
            freeaddrinfo(ai);
            sprintf_s(buf, "PASS %s\r\n", pass);
            send(sock, buf, strlen(buf), 0);
            sprintf_s(buf, "USER %s\r\n", nick);
            send(sock, buf, strlen(buf), 0);
            sprintf_s(buf, "NICK %s\r\n", nick);
            send(sock, buf, strlen(buf), 0);
            int bytesRecieved;
            while ((bytesRecieved = recv(sock, buf, 512, 0)) > 0) {

                std:cout << "\nbytesRecieved : " << bytesRecieved << "\n";
                std::cout << "DATA : " << buf;

                if (!strncmp(buf, "PING ", 5)) {
                    const char * pong = "PONG ";
                    send(sock, pong, strlen(pong), 0);
                }
                if (buf[0] != ':') continue;
                if (!strncmp(strchr(buf, ' ') + 1, "001", 3)) {
                    sprintf_s(buf, "JOIN %s\r\n", chan); 
                    send(sock, buf, strlen(buf), 0);
                }
            }
#ifdef _WIN32
            closesocket(sock);
            WSACleanup();
#else
            close(sock);
#endif

    return 0;
}

如果包含多个以'/ n'分隔的多个字符串,那么将recv buf拆分为多个字符串的最佳方法是什么?并迭代他们?如何处理在缓冲区末尾和下一个缓冲区开头分割的潜在字符串?还有我如何处理utf-8字符?因为twitch irc bot接受了许多不同的语言字符?

非常感谢,我的C ++技能非常基础,我主要是试图将这个机器人转换为我在python中编写的一个简单的机器人,它有很多很简单的处理字符串的方法。如果你可以解释事情,好像你正在与白痴打交道,我会很感激。

----编辑----

我想我需要做一些事情:

        for (int i = 0; i > bytesRecieved; i++) {

            string stringbuilder;
            stringbuilder.push_back(buf[i]);

        }

迭代char缓冲区并通过读取它们来构建单独的字符串,直到'/ n'字符然后执行下一个字符串并将它们放入字符串的向量(?)中?然后对这个向量进行交互,我不知道如何在c中做任何想法?我已经尝试了下面的升级库,但这最终会在最后创建一个带有大量无意义字符的字符串。

2 个答案:

答案 0 :(得分:1)

我会检查boost::tokenizer是否将字符串拆分为多个子字符串以基于分隔符进行迭代。您需要将字符串存储在std::string中以将其传递给Tokenizer。例如:

using sep = boost::char_separator<char>;
using tokenizer = boost::tokenizer<sep>;
constexpr auto separators = "\n";
const auto socket_string = std::string(/*values from socket go here*/);
const auto tokens = tokenizer(socket_string, sep(separators));
for(const token : tokens)
/* 
 * this loop will iterate over all the lines received from the socket,
 * one line at a time
 */
{
    /* token represents a single line of input */
}

当涉及将字符串拆分为多个缓冲区时......您必须有一些方法来检测它。我在通过套接字发送消息时工作的地方,我们在消息前加上一个表示消息中字节数的整数,这样我们就可以检查接收到的字符串的大小,知道我们是否完成了。如果没有这样的API,你将不得不决定解析字符串并决定你是否收到了所有内容。或者只是让它变得愚蠢和简单,并将每个缓冲区解析为一个新字符串。在您的情况下,也许如果您从缓冲区读取的字符串未在'\n'中结束,那么它还没有完成?这可能是我要检查的,但我不知道你所有的限制。

如何处理UTF-8字符取决于您的平台。在* nix框中,我认为std::string默认为UTF-8编码。在Windows上,您可能需要使用std::wstring

另外,我建议reading up on idiomatic C++。您的代码约为90%Pure C.

答案 1 :(得分:0)

最后,我通过遍历buf char数组并将每个char推到新字符串的末尾来解决了这个问题。当我遇到'/ n'字符时,我将新字符串添加到向量中并使用clear()函数重置字符串。

这一直持续到char数组的长度,直到recv返回的索引表示有效字节。

然后在for循环中迭代向量。

        std::vector <string> vs;
        string newString;
        for (int i = 0; i < bytesRecieved; i++) {
            newString.push_back(buf[i]);
            if (buf[i] == '\n') {
                vs.push_back(newString);
                newString.clear();
            }

        }

        for (const auto &item_vs : vs) {
            // This is where the recv buffer lines are iterated over
            cout << "Value : ";
            cout << item_vs;
        }