linux多进程子进程继承,Linux子进程继承父进程的文件描述符

一、子进程继承父进程的普通文件描述符

#include

#include

#include

#include

#include

#include

#include

int main()

{

char buf[1024]={0};

pid_t pid;

int ret=0;

int fd = open("./temp.txt", O_CREAT|O_TRUNC|O_RDWR, 0666);

if( fd == -1 ){

perror("open ./temp.txt");

return -1;

}

if ((pid = fork()) < 0) {

perror("fork");

return -1;

}

else if (pid == 0) {//child process

sleep(1);

ret = sprintf(buf, "child process pid:%d,parent pid:%d\n", getpid(), getppid());

write(fd, buf, ret);

close(fd);

exit(0);

}

else {//parent process

ret = sprintf(buf, "parent process pid:%d, child pid:%d\n", getpid(), pid);

write(fd, buf, ret);

close(fd);

}

waitpid(pid, NULL, 0);

return 0;

}

运行结果如下: [root@lghvm001 multi_process]# gcc inherit_fd.c

[root@lghvm001 multi_process]# ./a.out

[root@lghvm001 multi_process]# cat temp.txt

parent process pid:18028, child pid:18029

child process pid:18029,parent pid:18028

结论:子进程继承了父进程已经打开了的文件描述符。

二、子进程继承父进程的TCP Socket

写一个简单的TCP Server回射程序,即客户端给服务器端发一段字符串,服务器端将字符串原样返回。这里服务器端的Server程序采用主进程+工作进程的模式:主进程负责接收客户端的连接请求,然后fork一个子进程(也叫工作进程)来处理客户端的请求数据,即子进程接收客户端发来的字符串,然后将字符串原样返回给客户端。这里主要演示子进程继承父进程的TCP Socket,下面来看代码:

tcp_server.c

/* tcp_server.c */

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define MAXLINE 1024

#define BACKLOG 50

int main(int argc, char** argv)

{

int listenfd, connfd, n = 0;

struct sockaddr_in servaddr, cliaddr;

pid_t pid;

socklen_t clilen;

signal(SIGCHLD, SIG_IGN); //避免子进程成为僵尸进程

if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){

printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);

return -1;

}

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = AF_INET; //IPv4

servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //自动填入本机的IP地址

/*

if( inet_pton(AF_INET, "172.23.1.180", &servaddr.sin_addr) <= 0){ // [将“点分十进制”ip-> 网络字节序“整数”ip]

printf("inet_pton error for %s\n","172.23.1.180");

return -1;

}

*/

servaddr.sin_port = htons(6666); //将端口号转换为网络字节序

if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){

printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);

return -1;

}

if( listen(listenfd, BACKLOG) == -1){

printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);

return -1;

}

printf("======waiting for client's connect requestion======\n");

while(1){

if( (connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen)) == -1){

printf("accept socket error: %s(errno: %d)", strerror(errno),errno);

continue;

}

if ((pid = fork()) < 0) {

perror("fork");

return -1;

}

else if (pid == 0) {//child process

char buff[MAXLINE];

close(listenfd);

fprintf(stdout, "Connected, client addr: %s\n", inet_ntoa(cliaddr.sin_addr));

if((n = recv(connfd, buff, MAXLINE-1, 0)) < 0) {

printf("Failed to receive bytes from client\n");

return -1;

}

buff[n] = '\0';

fputs("recv msg from client: ", stdout);

fputs(buff, stdout);

while (n > 0) {

if (send(connfd, buff, n, 0) != n) {

printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);

return -1;

}

if((n = recv(connfd, buff, MAXLINE-1, 0)) < 0) {

printf("Failed to receive bytes from client\n");

return -1;

}

buff[n] = '\0';

fputs(buff, stdout);

}

close(connfd);

exit(0);

}

else {//parent process

close(connfd);

continue;

}

}

return 0;

}

客户端代码tcp_client.c

/* tcp_client.c */

#include

#include

#include

#include

#include

#include

#include

#define MAXLINE 1024

int main(int argc, char** argv)

{ int sockfd, n, received;

int len, bytes;

char recvline[MAXLINE], sendline[MAXLINE];

struct sockaddr_in servaddr;

/*if( argc != 2){

printf("usage: ./client \n");

exit(0);

}*/

memset(recvline, 0, MAXLINE);

memset(sendline, 0, MAXLINE);

if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){

printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);

return -1;

}

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(6666);

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

/*

if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){

printf("inet_pton error for %s\n",argv[1]);

return -1;

}*/

if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){

printf("connect error: %s(errno: %d)\n", strerror(errno),errno);

return -1;

}

printf("send msg to server: \n");

while(1) {

fgets(sendline, MAXLINE, stdin);

len = strlen(sendline);

if( send(sockfd, sendline, len, 0) != len) {

printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);

return -1;

}

fputs("echo from server:\n", stdout);

received = 0;

while(received < len) {

bytes = 0;

if ((bytes = recv(sockfd, recvline, MAXLINE-1, 0)) == -1 ){

perror("recv");

return -1;

}

else if(bytes == 0) {

printf("recv fail:the server has closed the connection prematually!\n");

return -1;

}

received += bytes;

recvline[bytes] = '\0';

fputs(recvline, stdout);

}

fputs("\n", stdout);

}

close(sockfd);

return 0;

}

打开linux的命令行终端,编译运行tcp_server

另外再打开两个命令行终端,编译运行tcp_client

运行结果如下:

tcp_server

[root@lghvm001 multi_process]# gcc tcp_server.c -o tcp_server

[root@lghvm001 multi_process]# ./tcp_server

======waiting for client's connect requestion======

Connected, client addr: 255.127.0.0

recv msg from client: hi,this is client1.

Connected, client addr: 127.0.0.1

recv msg from client: hi, this is client2.

tcp_client1

[root@lghvm001 multi_process]# gcc tcp_client.c -o tcp_client

[root@lghvm001 multi_process]# ./tcp_client

send msg to server:

hi,this is client1.

echo from server:

hi,this is client1.

tcp_client2

[lgh@lghvm001 multi_process]$ ./tcp_client

send msg to server:

hi, this is client2.

echo from server:

hi, this is client2.

该示例有多少个客户端连接就会产生多少个子进程,目前有主进程,两个子进程:

[lgh@lghvm001 Desktop]$ ps -ef | grep tcp_server

root 18302 43605 0 14:08 pts/14 00:00:00 ./tcp_server

root 18309 18302 0 14:09 pts/14 00:00:00 ./tcp_server

root 18311 18302 0 14:09 pts/14 00:00:00 ./tcp_server

lgh 18313 18132 0 14:09 pts/22 00:00:00 grep tcp_server

[lgh@lghvm001 Desktop]$ 若客户端连接太多,会导致多过的子进程,可以使用多路IO复用进行优化,在Linux下epoll是不二选择。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值