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

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

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

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 <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <errno.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>   
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <signal.h>


#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<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
#include<errno.h>  
#include<sys/types.h>  
#include<sys/socket.h>  
#include<netinet/in.h>  

#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 <ipaddress>\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是不二选择。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值