进程通信是指,两个不同进程之间可以相互交换数据。
由于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;
}