TCP/IP网络编程学习(11):管道通信

进程通信是指,两个不同进程之间可以相互交换数据。
由于fork产生的子进程复制了父进程的所有信息,但是也没有进行内存空间共享。需要使用别的方法。

通过管道进行进程数据交换

管道属于操作系统,进程只是拥有管道的文件描述符。

int pipe(int fd[2);
//成功返回 0,失败-1
//fd[0] 管道出口, 接收数据文件描述符
//fd[1] 管道入口,写入数据文件描述符

进程创建管道之后拥有其两个描述符。可以读写管道的数据,父进程如需和子进程进行数据交换,那么fork一个子进程即可。此时父进程使用fd[0],子进程使用fd[1]即可。

#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE 30

int main(int argc, char *argv[]){
	int fds[2];
	char str[]="Who are you?";
	char buf[BUF_SIZE];
	pid_t pid;
	pipe(fds);//父进程同时拥有管道的两个文件描述符,fork之后传递给子进程
	pid=fork();
	if(pid==0){
		write(fds[1], str, sizeof(str));//子进程写
	}
	else{
		read(fds[0], buf, BUF_SIZE);//父进程读
		puts(buf);
	}
	return 0;
}

在这里插入图片描述
数据进入管道后成为无主数据 。也就是通过read函数先读取数据的进程将得到数据。即使该进程将数据传到了管道。因此如果需要双向通信,需要建立两个管道。
在这里插入图片描述

int fds1[2], fds2[2];
	char str1[]="Who are you?";
	char str2[]="Thank you for your message";
	char buf[BUF_SIZE];
	pid_t pid;
	
	pipe(fds1), pipe(fds2);
	pid=fork();
	
	if(pid==0){
		write(fds1[1], str1, sizeof(str1));
		read(fds2[0], buf, BUF_SIZE);
		printf("Child proc output: %s \n",  buf);
	}
	else{
		read(fds1[0], buf, BUF_SIZE);
		printf("Parent proc output: %s \n", buf);
		write(fds2[1], str2, sizeof(str2));
		sleep(3);
	}

保存消息的回声服务器

将客户端传输的字符串按序保存到文件中

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 100
void error_handling(char *message);//错误处理函数
void read_childproc(int sig);//子进程终止时调用函数

int main(int argc, char *argv[])
{
	int serv_sock, clnt_sock;//定义服务端套接字和与客户端连接的套接字
	struct sockaddr_in serv_adr, clnt_adr;
	struct sigaction act;//信号处理
	
	if(argc!=2) {
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}

	//注册信号
	act.sa_handler=read_childproc;
	sigemptyset(&act.sa_mask);
	act.sa_flags=0;
	int state=sigaction(SIGCHLD, &act, 0);
	
	//创建服务端套接字
	serv_sock=socket(PF_INET, SOCK_STREAM, 0);
	memset(&serv_adr, 0, sizeof(serv_adr));
	serv_adr.sin_family=AF_INET;
	serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
	serv_adr.sin_port=htons(atoi(argv[1]));
	
	//绑定地址信息到套接字上
	if(bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr))==-1)
		error_handling("bind() error");
	//监听状态
	if(listen(serv_sock, 5)==-1)
		error_handling("listen() error");
	
	int fds[2];
	pid_t pid;
	
	pipe(fds);
	pid=fork();
	if(pid==0)//创建子进程保存信息,使用管道和其他进程进行通信
	{
		FILE * fp=fopen("echomsg.txt", "wt");
		char msgbuf[BUF_SIZE];
		int i, len;

		for(i=0; i<10; i++)
		{
			len=read(fds[0], msgbuf, BUF_SIZE);
			fwrite((void*)msgbuf, 1, len, fp);
		}
		fclose(fp);
		return 0;
	}
	socklen_t adr_sz;
	int str_len;
	while(1){//父进程
		adr_sz=sizeof(clnt_adr);
		clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
		//与客服端连接的套接字
		if(clnt_sock==-1)
			continue;
		else
			puts("new client connected...");

		pid=fork();
		//创建子进程接收数据并把数据写回客户端和管道保存在本地。如果多个客户端连接,
		//那么都将写入到一个文件中。
		if(pid==0){
			close(serv_sock);
			while((str_len=read(clnt_sock, buf, BUF_SIZE))!=0){
				write(clnt_sock, buf, str_len);
				write(fds[1], buf, str_len);
			}
			clese(clnt_sock);
			puts("client disconnected...");
			return 0;
		}
		else
			close(clnt_sock);
	}
	close(serv_sock);
	return 0;
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值