且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Ç的recv()读取,直到出现新行

更新时间:2023-12-03 20:09:22

通常的方式来处理这是的recv 到应用程序中的持久缓冲区,然后拉单个线路输出和处理它。稍后,您可以再次调用的recv 前处理缓冲区中剩余的行。请记住,在缓冲器中的最后一行仅可部分地接收;你必须通过重新输入的recv 来处理这种情况下结束此行。

下面是一个例子(没有经过测试也将查找 \\ n ,而不是 \\ r \\ n !):

 的#define BUFFER_SIZE 1024
烧焦INBUF [BUFFER_SIZE];
为size_t inbuf_used = 0;/ *最终\\ n被调用之前process_line替换\\ 0 * /
无效process_line(字符* lineptr);
无效input_pump(INT FD){
  为size_t buf_remain = sizeof的(INBUF) - inbuf_used;
  如果(buf_remain == 0){
    fprintf中(标准错误,行超过缓冲区长度\\ n!);
    中止();
  }  ssiz​​e_t供RV =的recv(FD(无效*)及INBUF [inbuf_used],inbuf_remain,MSG_DONTWAIT);
  如果(RV == 0){
    fprintf中(标准错误,连接关闭\\ n);
    中止();
  }
  如果(RV&℃的放大器;&放大器;错误号== EAGAIN){
    / *现在没有数据,回拨时,插座是可读的* /
    返回;
  }
  如果(RV,小于0){
    PERROR(连接错误);
    中止();
  }
  buf_used + = RV;  / *扫描该行缓冲器换行符;我们非常小心这里处理嵌入的\\ 0
   *一个邪恶的服务器可以发送,以及那些只完成加工流水线。
   * /
  字符* LINE_START = INBUF;
  字符* LINE_END;
  而((LINE_END =(字符*)了memchr((无效*)LINE_START,'\\ n',inbuf_used - (LINE_START - INBUF))))
  {
    * LINE_END = 0;
    process_line(LINE_START);
    LINE_START = LINE_END + 1;
  }
  / *移位缓冲下来,未经处理的数据是在开始* /
  inbuf_used - =(LINE_START - INBUF);
  memmove与(innbuf,LINE_START,inbuf_used);
}

I'm working on writing a IRC bot in C, and have ran into a snag.

In my main function, I create my socket and connect, all that happy stuff. Then I have a (almost) infinite loop to read what's being sent back from the server. I then pass what's read off to a helper function, processLine(char *line) - the problem is, that the following code reads until my buffer is full - I want it to only read text until a newline (\n) or carriage return (\r) occurs (thus ending that line)

   while (buffer[0] && buffer[1]) {
        for (i=0;i<BUFSIZE;i++) buffer[i]='\0';
        if (recv(sock, buffer, BUFSIZE, 0) == SOCKET_ERROR)
            processError();

        processLine(buffer);
    }

What ends up happening is that many lines get jammed all together, and I can't process the lines properly when that happens.

If you're not familiar with IRC protocols, a brief summary would be that when a message is sent, it often looks like this: :YourNickName!YourIdent@YourHostName PRIVMSG #someChannel :The rest on from here is the message sent... and a login notice, for instance, is something like this: :the.hostname.of.the.server ### bla some text bla with ### being a code(?) used for processing - i.e. 372 is an indicator that the following text is part of the Message Of The Day.

When it's all jammed together, I can't read what number is for what line because I can't find where a line begins or ends!

I'd appreciate help with this very much!

P.S.: This is being compiled/ran on linux, but I eventually want to port it to windows, so I am making as much of it as I can multi-platform.

P.S.S.: Here's my processLine() code:

void processLine(const char *line) {
    char *buffer, *words[MAX_WORDS], *aPtr;
    char response[100];
    int count = 0, i;
    buffer = strdup(line);

    printf("BLA %s", line);

    while((aPtr = strsep(&buffer, " ")) && count < MAX_WORDS)
        words[count++] = aPtr;
        printf("DEBUG %s\n", words[1]);
    if (strcmp(words[0], "PING") == 0) {
        strcpy(response, "PONG ");
        strcat(response, words[1]);
        sendLine(NULL, response); /* This is a custom function, basically it's a send ALL function */
    } else if (strcmp(words[1], "376") == 0) { /* We got logged in, send login responses (i.e. channel joins) */
        sendLine(NULL, "JOIN #cbot");
    }
}

The usual way to deal with this is to recv into a persistent buffer in your application, then pull a single line out and process it. Later you can process the remaining lines in the buffer before calling recv again. Keep in mind that the last line in the buffer may only be partially received; you have to deal with this case by re-entering recv to finish the line.

Here's an example (totally untested! also looks for a \n, not \r\n):

#define BUFFER_SIZE 1024
char inbuf[BUFFER_SIZE];
size_t inbuf_used = 0;

/* Final \n is replaced with \0 before calling process_line */
void process_line(char *lineptr);
void input_pump(int fd) {
  size_t buf_remain = sizeof(inbuf) - inbuf_used;
  if (buf_remain == 0) {
    fprintf(stderr, "Line exceeded buffer length!\n");
    abort();
  }

  ssize_t rv = recv(fd, (void*)&inbuf[inbuf_used], inbuf_remain, MSG_DONTWAIT);
  if (rv == 0) {
    fprintf(stderr, "Connection closed.\n");
    abort();
  }
  if (rv < 0 && errno == EAGAIN) {
    /* no data for now, call back when the socket is readable */
    return;
  }
  if (rv < 0) {
    perror("Connection error");
    abort();
  }
  buf_used += rv;

  /* Scan for newlines in the line buffer; we're careful here to deal with embedded \0s
   * an evil server may send, as well as only processing lines that are complete.
   */
  char *line_start = inbuf;
  char *line_end;
  while ( (line_end = (char*)memchr((void*)line_start, '\n', inbuf_used - (line_start - inbuf))))
  {
    *line_end = 0;
    process_line(line_start);
    line_start = line_end + 1;
  }
  /* Shift buffer down so the unprocessed data is at the start */
  inbuf_used -= (line_start - inbuf);
  memmove(innbuf, line_start, inbuf_used);
}