使用jsonrpc-c服务器fork子进程时如何让客户端正常退出?
问题描述
我正在使用jsonrpc-c开发一个远程shell玩具。客户端通过nc向服务器发送请求,命令如下:
echo "{\"method\":\"sayHello\"}" | nc localhost 1234
服务器代码示例如下:
#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <signal.h> #include "jsonrpc-c.h" #define DEFAULT_PORT 1234 //the port users will be connecting to static struct jrpc_server my_server; cJSON * hello(jrpc_context * ctx, cJSON * params, cJSON *id) { pid_t pid = fork(); if (pid==0) { freopen( "/dev/null", "w", stdout ); freopen( "/dev/null", "r", stdin ); signal(SIGCHLD,SIG_IGN); while(true){ printf("hello in child\n"); } exit(1); } printf("hello in father\n"); return cJSON_CreateString("done"); } void main(int argc, char **argv) { int port; if (argc == 2) port = atoi(argv[1]); else port = DEFAULT_PORT; jrpc_server_init(&my_server, (int)port); jrpc_register_procedure(&my_server, hello, "sayHello", NULL); jrpc_server_run(&my_server); jrpc_server_destroy(&my_server); }
执行上述客户端命令时,客户端会永久阻塞。请问如何实现服务器父进程返回响应后客户端正常退出,同时让服务器子进程持续运行?
问题原因与解决方法
原因分析
客户端nc阻塞的核心原因是:子进程继承了父进程的客户端连接套接字,导致这个套接字的引用计数不为0,服务器父进程返回响应后并没有真正关闭连接,nc一直等待连接关闭信号,所以永久阻塞。
解决步骤
要解决这个问题,需要在子进程中主动关闭继承的套接字,同时调整信号处理逻辑的位置。具体修改如下:
- 获取当前连接的套接字:jsonrpc-c的
jrpc_context结构体中包含了客户端连接的文件描述符(通常为ctx->conn_fd,若字段名称不同,替换为库中对应字段即可)。 - 子进程中关闭套接字:在子进程代码块中添加关闭该套接字的操作,释放连接引用。
- 调整信号处理位置:将
signal(SIGCHLD,SIG_IGN)移到父进程中,避免子进程修改父进程的信号处理规则。
修改后的hello函数代码:
cJSON * hello(jrpc_context * ctx, cJSON * params, cJSON *id) { pid_t pid = fork(); if (pid == 0) { // 关闭继承的客户端连接套接字,释放连接引用 close(ctx->conn_fd); freopen( "/dev/null", "w", stdout ); freopen( "/dev/null", "r", stdin ); while(true){ printf("hello in child\n"); sleep(1); // 避免子进程无限制循环占用CPU } exit(EXIT_FAILURE); } // 父进程忽略子进程退出信号,防止产生僵尸进程 signal(SIGCHLD, SIG_IGN); printf("hello in father\n"); return cJSON_CreateString("done"); }
额外优化说明
- 子进程中的
printf已被重定向到/dev/null,添加sleep(1)可以避免子进程持续占用CPU资源。 - 若
ctx->conn_fd不是正确的连接描述符字段,可查看jsonrpc-c的头文件,找到对应表示客户端套接字的成员。
内容的提问来源于stack exchange,提问作者plznobug
相关产品推荐
相关产品推荐

