我对C的了解非常有限。我试图将从客户端传递给服务器的String标记化,因为我想使用传递给execve
的参数。通过buffer
传递的参数需要复制到*argv
并进行标记,以便可以使用buffer
,argv[0]
访问argv[1]
个令牌,等。显然我做错了什么。
n = read(sockfd, buffer, sizeof(buffer));
strcpy(*argv, buffer);
printf("buffer:%s\n", buffer);
printf("argv:%s\n", *argv);
printf("argv[0]:%s\n", argv[0]);
printf("argv[1]:%s\n", argv[1]);
*argv = strtok_r(*argv, " ", argv);
printf("argv:%s\n", *argv);
i = fork();
if (i < 0) {
//Close socket on fork error.
perror("fork");
exit(-1);
} else if (i == 0) {
//execve on input args
execve(argv[0], &argv[0], 0);
exit(0);
} else {
wait(&status);
//close(sockfd);
}
传递参数&#34; / bin / date -u&#34;使用上面的代码给出了输出:
buffer:/bin/date -u
argv:/bin/date -u
argv[0]:/bin/date -u
argv[1]:(null)
我的输出是什么:
buffer:/bin/date -u
argv:/bin/date -u
argv[0]:/bin/date
argv[1]:-u
我尝试使用strtok_r()
,但它没有像我预期的那样工作。我插入的片段是:
*argv = strtok_r(*argv, " ", argv);
printf("argv:%s\n", *argv);
,输出为argv:/bin/date
。
先谢谢了,SO。
编辑:我不必像上面那样明确地标记buffer
。任何从客户端获取参数的方法都可以正常工作。
答案 0 :(得分:3)
嗯,您正在处理几个问题。第一个是选择argv
作为你正在编写缓冲区的可变量。虽然它只是一个指针数组,但您通常会将argv
视为保存参数的数组传递给即时进程,而不是作为要修改的变量。然而,这确实是语义学,我知道没有禁止这样做。但是,您无法在将令牌分配给*argv
的同时对*argv
进行标记,因为strtok_r
会在此过程中修改*argv
。
除此之外,真正的问题似乎是使用strtok_r
。看看man strtok_r
。为了对字符串进行标记,您需要对strtok_r
进行重复调用,以便提取所有标记。使用第一个参数(* argv ...)对strtok_r
的第一次调用仅提取第一个标记。为了完成提取,您必须将NULL
作为第一个参数传递,直到所有标记都被提取为止。此外,您从中提取标记的字符串将通过调用strtok_r
进行修改,并且不应在提取后使用。通常,如果稍后需要,则会生成字符串的副本以保留原始字符串。
在您的代码中,您只需拨打strtok_r
一次E.g:
*argv = strtok_r(*argv, " ", argv); // extracts the first token and modifies *argv
如果您的目的是提取所有字符串,那么您需要重复调用strtok_r
之类的内容:
char *token = malloc (sizeof (token) * 128); // or something large enough to hold the tokens
token = strtok_r(*argv, " ", argv);
if (token)
printf (" token: %s\n", token);
while ((token = strtok_r (NULL, " ", argv)) != NULL)
{
printf (" token: %s\n", token);
}
您可以随意捕获各个令牌,以便将它们传递给execve
。但是,在argv
写回argv
的同时,您无法从argv
中剥离出来。如上所述,strtok_r
在提取期间由{{1}}修改,因此您需要一个单独的数组来保存令牌。希望这会有所帮助。
答案 1 :(得分:0)
strtok()
和strtok_r()
函数一次返回一个令牌。它们在调用之间保持状态,您需要在循环中调用它们以将字符串拆分为标记。他们还修改了作为第一个参数就地传递的缓冲区,因此你需要复制它。
让我举个例子:
#include <stdio.h>
#include <string.h>
#define MAX_CMD_SIZE 1024
#define MAX_ARG_COUNT 10
main()
{
const char *command = "/bin/test arg1 arg2 arg3 arg4 arg5";
/* Allocate a buffer for tokenization.
* the strtok_r() function modifies this buffer in-place and return pointers
* to strings located inside this buffer. */
char cmd_buf[MAX_CMD_SIZE] = { 0 };
strncpy(cmd_buf, command, sizeof(cmd_buf));
/* This strtok_r() call puts '\0' after the first token in the buffer,
* It saves the state to the strtok_state and subsequent calls resume from that point. */
char *strtok_state = NULL;
char *filename = strtok_r(cmd_buf, " ", &strtok_state);
printf("filename = %s\n", filename);
/* Allocate an array of pointers.
* We will make them point to certain locations inside the cmd_buf. */
char *args[MAX_ARG_COUNT] = { NULL };
/* loop the strtok_r() call while there are tokens and free space in the array */
size_t current_arg_idx;
for (current_arg_idx = 0; current_arg_idx < MAX_ARG_COUNT; ++current_arg_idx) {
/* Note that the first argument to strtok_r() is NULL.
* That means resume from a point saved in the strtok_state. */
char *current_arg = strtok_r(NULL, " ", &strtok_state);
if (current_arg == NULL) {
break;
}
args[current_arg_idx] = current_arg;
printf("args[%d] = %s\n", current_arg_idx, args[current_arg_idx]);
}
}
以上示例的输出为:
filename = /bin/test
args[0] = arg1
args[1] = arg2
args[2] = arg3
args[3] = arg4
args[4] = arg5
请注意,我将filename
和args
放入单独的变量中,以说明第一个调用和后续调用之间的区别。对于execve()
,您通常希望将它们放入单个数组中,并将其称为execve(argv[0], argv, NULL);
,因为文件名应该是argv
中的第一个元素。