fork()后父子进程共享文件

fork函数的特点概括起来就是“调用一次,返回两次”,在父进程中调用一次,在父进程和子进程中各返回一次。
fork的另一个特性是所有由父进程打开的描述符都被复制到子进程中。父、子进程中相同编号的文件描述符在内核中指向同一个file结构体,也就是说,file结构体的引用计数要增加。

下面展示了一个返回本地时间给客户的简单客户-服务器模型,其中服务端为了并发处理来自客户的请求会调用fork创建一个子线程,
会复制文件描述符,父子进程相同的描述符指向同一个file结构体,close()一次时,引用计数由2变为1,
只有close()两次之后,服务端才会真正关闭。

#ifndef MY_NET_H
#define MY_NET_H

#include <sys/types.h>      
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <string.h>

#define MAXLINE 4096
#define SA struct sockaddr
#define LISTENEQ 10

/*err_quit*/
void err_quit(const char* err_string)
{
	printf("%s\n", err_string);
	exit(-1);
}

/*err_sys*/
void err_sys(const char* err_string)
{
	perror(err_string);
	exit(-1);
}

/*Socket*/
int Socket(int domain, int type, int protocol)
{
	int sockfd = socket(domain, type, protocol);
	if (sockfd == -1)
		err_sys("socket error");
	return sockfd;
}

/*Inet_pton*/
int Inet_pton(int af, const char *src, void *dst)
{
	int r;
	if ((r = inet_pton(af, src, dst)) <= 0)
		err_sys("inet_pton error");
	return r;
}

/*Connect*/
int Connect(int sockfd, 
			const struct sockaddr *addr,
            socklen_t addrlen)
{
	int r;
	if ((r = connect(sockfd, addr, addrlen)) == -1)
		err_sys("connect error");
	return r;
}

/*Bind*/
int Bind(int sockfd, 
		const struct sockaddr *addr,
        socklen_t addrlen)
{
	int r;
	r = bind(sockfd, addr, addrlen);
	if (r == -1)
		err_sys("bind error");
	return r;
}

/*Listen*/
int Listen(int sockfd, int backlog)
{
	int r;
	r = listen(sockfd, backlog);
	if (r == -1)
		err_sys("listen error");
	return r;
}

/*Accept*/
int Accept(int sockfd, 
		   struct sockaddr *addr, 
		   socklen_t *addrlen)
{
	int r;
	r = accept(sockfd, addr, addrlen);
	if (r == -1)
		err_sys("accept error");
	return r;
}

/*Close*/
int Close(int fd)
{
	int r = close(fd);
	if (r == -1)
		err_sys("close error");
	return r;
}

/*Read*/
int Read(int fd, void *buf, size_t count)
{
	int r;
	r = read(fd, buf, count);
	if (r == -1)
		err_sys("read error");
	return r;
}

/*Write*/
int Write(int fd, const void *buf, size_t count)
{
	int r;
	r = write(fd, buf, count);
	if (r == -1)
		err_sys("write error");
	return r;
}

#endif

客户
#include "net.h"

main(int argc, char **argv)
{
	int    sockfd, n;
	char   recvline[MAXLINE + 1];
	struct sockaddr_in servaddr;
	
	if (argc != 2)
		err_quit("2个参数\n");
		
	sockfd = Socket(AF_INET, SOCK_STREAM, 0);
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(9997);
	Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
	
	Connect(sockfd, (SA*)&servaddr, sizeof(servaddr));
	
	while ((n = Read(sockfd, recvline, MAXLINE)) != 0)
	{
		recvline[n] = 0;
		fputs(recvline, stdout);
	}
	printf("server closed\n");
	
	exit(0);
}

服务器
#include "net.h"

main(int argc, char **argv)
{
	int listenfd, connfd, n, i;
	struct sockaddr_in servaddr;
	char buf[MAXLINE];
	time_t ticks;
	
	listenfd = Socket(AF_INET, SOCK_STREAM, 0);
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(9997);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
	
	Listen(listenfd, LISTENEQ);
	
	while (1)
	{
		connfd = Accept(listenfd, (SA*)NULL, NULL);
		if (fork() == 0) //child
		{
			Close(listenfd);
			ticks = time(NULL);
			snprintf(buf, sizeof(buf), "%.24s\r\n", 
				 ctime(&ticks));
			for(i=0; i<strlen(buf); i++)
				Write(connfd, &buf[i], 1);
			sleep(10);
			Close(connfd);
			printf("child closed connfd\n");
			exit(0);	
		}
		Close(connfd);
		printf("parent closed connfd\n");
	}
}

接收到时间后,10S后客户端才会关闭。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值