【问题标题】:Best way to split char array received from socket拆分从套接字接收的字符数组的最佳方法
【发布时间】:2016-02-22 20:59:52
【问题描述】:

我正在编写一个简单的 HTTP 服务器,我需要解析传入的请求。

假设我读过类似下面的一行GET /file HTTP/1.1

我需要把它拆分成GET/file

我尝试了很多方法,但似乎都无法奏效。

问题是服务器在以下 while 循环中以块的形式读取传入的请求:

char echoBuffer[RCVBUFSIZE];
int recvMsgSize;

if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0)
        DieWithError("recv() failed");

while (recvMsgSize > 0) {

      if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0)
            DieWithError("recv() failed");
}

我在循环中尝试了以下方法:

char *token;
for (i = 0; i < 3; i++){
      switch (i) {
        case 0:
          token = strtok(echoBuffer, "/");
          printf("%s\n", token[i]);
        case 1:
          token = strtok(echoBuffer, "HTTP");
          printf("%s\n", token[i]);
      }
    }

但是所有这些打印都是GET 好几次。

我尝试定义一个字符串char *echoString 并使用strcat()

这只是一起失败,我希望因为缓冲区是一个字符数组。

那么我在这里有什么选择?

【问题讨论】:

  • 是什么让您认为strtok() 可以用于由recv() 填充的缓冲区?具体来说,您如何确保空终止?
  • 在使用任何类型的 str() 函数之前,您是否建议将 char 数组转换为 char*?我不确定如何确保空终止,除非它成功拼接 GET
  • stackoverflow.com/q/33618837/10396,尽管名字不好,但密切相关。您需要将其分为两个步骤:1)接收整个请求; 2) 标记数据。
  • 请注意,在这种情况下,接收整个请求意味着读取直到在输入流中找到\r\n\r\n
  • 请勿将strtok用于此目的(或任何实际目的),它会修改缓冲区并且不可重入

标签: c string char concat splice


【解决方案1】:

上面提到的cmets,你需要

  • 确定recv()调用返回的字符串格式
  • 标记收到的字符串

请注意,因为任何strtok() 系列函数,包括我在下面的实现,都依赖于静态变量,它们不是线程安全的!在这里要格外小心...

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

/* a dummy recv() implementation that returns the size
* of received buffer */
size_t recv_(int s, void *buf, size_t len,  int flags) {
    len=0;
    char *tmp=buf;

    for (; *tmp; ++tmp, ++len)
        ;

    return len;
}

/* Modified version of zstring_strtok
* first call        -> zstrint_strtok(char *str, char *delim, int len)
* consecutive calls -> zstrint_strtok(NULL, char *delim,0)
*/
char *zstring_strtok(char *str, const char *delim, int len) {
    static char *static_str=0;      /* var to store last address */
    int index=0, strlength=len;     /* integers for indexes */
    int found = 0;                  /* check if delim is found */

    /* delimiter cannot be NULL
    * if no more char left, return NULL as well
    */
    if (delim==0 || (str == 0 && static_str == 0))
        return 0;

    if (str == 0)
        str = static_str;

    /* get length of string */
    if (len==0)
        while(str[strlength])
            strlength++;
    else
        strlength=len;

    /* find the first occurance of delim */
    for (index=0;index<strlength;index++)
        if (str[index]==delim[0]) {
            found=1;
            break;
        }

    /* if delim is not contained in str, return str */
    if (!found) {
        static_str = 0;
        return str;
    }

    /* check for consecutive delimiters
    *if first char is delim, return delim
    */
    if (str[0]==delim[0]) {
        static_str = (str + 1);
        return (char *)delim;
    }

    /* terminate the string
    * this assignmetn requires char[], so str has to
    * be char[] rather than *char
    */
    str[index] = '\0';

    /* save the rest of the string */
    if ((str + index + 1)!=0)
        static_str = (str + index + 1);
    else
        static_str = 0;

        return str;
}


int main()
{
    char response[]="GET /file HTTP/1.1";
    char *buf;
    int recv_msg_size;

    buf=malloc(256);

    if((recv_msg_size=recv_(0,response,0,0)) > 0){
        buf=zstring_strtok(response," ",recv_msg_size);
        do{
            printf("%s\n",buf);
        } while(buf=zstring_strtok(NULL," ",0));
    }


    return 0;
}

zstring_strtok() 函数是the zString library, a BSD licensed string processing library for Czstring_strtok() 的修改版本。

上面的recv_() 函数是recv() 系统调用的虚拟替换,只是为了使示例代码对您更易读。在我的系统(FreeBSD 10.2-RELEASE)上,recv(3) 被定义为

 ssize_t
 recv(int s, void *buf, size_t len, int flags);

上面例子的输出是

% ./recv
GET
/file
HTTP/1.1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-18
    • 2021-03-18
    • 1970-01-01
    • 2013-11-28
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    • 1970-01-01
    相关资源
    最近更新 更多