我在从服务器中抽取一些函数时遇到了一些麻烦。特别是我的解析功能在子进程内部很难调试,我甚至无法在gdb中跟随它,因为当我遵循子进程时服务器正在跳循环?我认为在我的文字中显示代码可能比编写上下文更容易..
主要产卵循环
while (1) { /* accepting client connections */
addrlen = sizeof(client_addr);
/* create worker and accept traffic on listen_sock */
printf("Waiting for client connection\n");
if ((worker_sock = accept(listen_sock, (struct sockaddr*) &client_addr, &addrlen)) < 0) {
perror("Error accepting traffic on socket:"); continue;
}
inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *) &client_addr), s, sizeof(s));
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(listen_sock); // child doesn't need the listener
respond(worker_sock); // send response to client
// shutdown(worker_sock, SHUT_RDWR); // block connections
close(worker_sock); // destroy that old sock!
exit(0); // exit proc
} // end of child proc
close(worker_sock); // parent doesn't need this
}
回应功能(由孩子召唤)
/* serve response for client request */
void respond(int worker_sock) {
char *request[3], path[PATH_MAX] = {'\0'};
char recv_data[SOCK_BUFF_DEF_READ] = {'\0'};
char resp_data[SOCK_BUFF_DEF_WRITE] = {'\0'};
ssize_t bytes_read = 0;
int resourcefd;
/* TODO: change this to terminate on client req flag (header w/ size of req) */
/* read into buff full request */
if ((bytes_read = recv(worker_sock, recv_data, SOCK_BUFF_DEF_READ, 0)) < 0) {
fprintf(stderr, ("recv() error\n"));
} printf("File: %s\nFunction: %s()\nLine Number: %d\nbytes_read: %d, MAX: %d\n",__FILE__,__FUNCTION__,__LINE__, bytes_read, SOCK_BUFF_MAX_READ);
/* error checking buffer overflow checking */
if (bytes_read == 0 || bytes_read > SOCK_BUFF_MAX_READ) {
fprintf(stderr, ("recv() error\n"));
/* send error response */
}
Request request00 = parseRequest(recv_data);
正在进行解析器的抽象
typedef struct request Request;
struct request {
unsigned char info; /* request method / proto */
char *path; /* path to resource */
Dict *headers; /* http headers */
char *body; /* body of request */
};
/* parse request line from a client request */
Request parseRequest(char *req) {
int i;
printf("processing client request\n");
size_t *num_tokens = malloc(sizeof(size_t)); /* num of tokens */
char **tokens = strsplit(req, " \r\n", num_tokens); /* parse it */
printf("File: %s\nFunction: %s()\nLine Number: %d\n",__FILE__,__FUNCTION__,__LINE__);
printf("num_tokens: %zi\n", *num_tokens);
for (i = 0; i < *num_tokens; i++) {
printf("token: %s\n", tokens[i]);
}
printf("File: %s\nFunction: %s()\nLine Number: %d\n",__FILE__,__FUNCTION__,__LINE__);
Request retreq = {
.info = 0, /* method, proto, validity */
.path = (char *) malloc(sizeof(char *)), /* request path or URI */
.headers = initDict(50), /* limit to 50 headers */
.body = (char *) malloc(sizeof(char *)) /* body of request */
};
return retreq;
}
我确定孩子已经挂在了strSplit函数上(我的strtok_r实现),但是该函数已经过彻底的测试,并且在我的其他实现中仍然有效,所以我很难理解为什么孩子的上下文在调用中有所不同这个函数,strsplit也发布在下面。
strSplit
char **strsplit(char *str, const char delims[], size_t *len) {
char *save; /* holds str_tok val btwn calls */
char **result = '\0'; /* set result to NULL */
char *tmp = strdup(str); /* leaves original str intact */
size_t delims_size = strlen(delims);
size_t count = 0; /* number of main strings */
size_t sub_count = 0; /* number of substrings */
/* get number of delims in str and malloc */
while ((tmp = strstr(tmp, delims)) != NULL) {
tmp += delims_size;
count++;
}
result = malloc(sizeof(char*) * count);
if (result) {
/* reset counter and tmp */
count = 0;
free(tmp);
tmp = strdup(str);
/* grab the first token */
char* token = strtok_r(tmp, delims, &save);
result[count] = strdup(token);
while (token) {
token = strtok_r(NULL, delims, &save);
if (token != NULL) {
result[++count] = strdup(token);
}
else { /* set last ptr to NULL */
result[++count] = '\0';
}/* add one for trailing token */
} *len = count;
}
else {
*len = 0;
}
free(tmp);
return result;
}
如果有人知道如何更好地调试这个我的全部耳朵..当设置gdb与“set follow-fork-mode child”时,它会尝试跟随孩子,但是父母跳出循环(它应该是无限直到信号停止它)并因此结束程序..