c recv()读取直到换行发生

我正在用C编写一个IRC机器人,并遇到了麻烦。

在我的主要function中,我创建了我的套接字并连接,所有这些快乐的东西。 然后我有一个(几乎)无限循环来读取从服务器发回的内容。 然后我将读取的内容传递给辅助函数processLine(char *line) – 问题是,以下代码读取直到我的缓冲区已满 – 我希望它只读取文本直到换行符(\ n)或回车符(\ r)发生(从而结束该行)

  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); } 

最终发生的事情是,许多线路都被卡在一起,当发生这种情况时,我无法正确处理线路。

如果您不熟悉IRC协议,可以简要总结一下,当发送消息时,它通常如下所示:YourNickName!YourIdent@YourHostName PRIVMSG #someChannel :The rest on from here is the message sent...例如,登录通知是这样的:the.hostname.of.the.server ### bla some text bla ,###是用于处理的代码(?) – 即372是一个指示符以下文字是每日信息的一部分。

当它全部卡在一起时,我无法读取什么行的数字,因为我找不到行开始或结束的位置!

我非常感谢你的帮助!

PS:这是在Linux上编译/运行,但我最终想把它移植到Windows,所以我尽可能多地制作它。

PSS:这是我的processLine()代码:

 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 (ie channel joins) */ sendLine(NULL, "JOIN #cbot"); } } 

处理此问题的常用方法是在应用程序中重新进入持久缓冲区,然后拉出一行并处理它。 稍后您可以在再次调用recv之前处理缓冲区中的剩余行。 请记住,缓冲区中的最后一行只能部分接收; 你必须通过重新输入recv来完成这条线来处理这个案子。

这是一个例子(完全未经测试!也寻找\n ,而不是\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 inbuf_remain = sizeof(inbuf) - inbuf_used; if (inbuf_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(); } inbuf_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); } 

TCP不提供任何类型的排序。 正如@bdonlan已经说过你应该实现类似的东西:

  • 从套接字连续recv到缓冲区
  • 在每个recv ,检查收到的字节是否包含\n
  • 如果\n使用缓冲区中的所有内容(并清除它)

我对此没有很好的感觉(我在某处读到你不应该将低级I / O与stdio I / O混合在一起)但你可能能够使用fdopen

你需要做的就是

  • 使用fdopen(3)将套接字与FILE *关联FILE *
  • 使用setvbuf告诉stdio你想要它行缓冲( _IOLBF )而不是默认的块缓冲。

在这一点上,你应该有效地将工作从你的手移到stdio 。 然后你可以继续在FILE *上使用fgets等。