TCP/IP网络编程——进程间通信IPC

下面以管道pipe完成进程间的通信:开辟进程将回声客户端传输的字符串按序保存到文件中,这里读字符串信息用到了管道通信。

echo_storeserv.c

//将回声客户端传输的字符串按序保存到文件,利用到了进程间通信(管道)
//int pipe(int fds[2]);
//fds[0]:接收数据文件描述符,管道出口。fds[1]:发送数据文件描述符,管道入口
//write向管道写入数据,read读走管道数据
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <signal.h>
#include <sys/wait.h>

#define BUF_SIZE 30

void error_handling(char *message);
void read_childproc(int sig);

int main(int argc, char *argv[])
{
  //定义TCP连接变量
  int serv_sock;
  int clnt_sock;
  struct sockaddr_in serv_addr;
  struct sockaddr_in clnt_addr;
  socklen_t clnt_addr_size;
  int str_len;
  char buf[BUF_SIZE];
  //定义信号处理变量
  pid_t pid;
  struct sigaction act;
  int state;
  //pipe变量
  int fds[2];
  
  if(argc!=2)
  {
    exit(1);
  }
  //配置信号处理函数,一旦有进程结束就调用这个函数
  act.sa_handler=read_childproc;
  sigemptyset(&act.sa_mask);
  act.sa_flags=0;
  sigaction(SIGCHLD, &act, 0);
  
  //TCP套接字配置
  serv_sock=socket(PF_INET, SOCK_STREAM, 0);
  if(serv_sock == -1)
    error_handling("socket error!");

  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;	//IPV4协议族
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);	//主机字节序(host)转换成网络字节序(net)(大端序)
  serv_addr.sin_port = htons(atoi(argv[1]));	//端口号
  if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
    error_handling("bind error");

  if(listen(serv_sock, 5) == -1)
    error_handling("listen error");
  
  //开辟新进程用来写入文件
  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;
  }
  
  while(1)
  {
    clnt_addr_size = sizeof(clnt_addr);
    clnt_sock=accept(serv_sock, (struct sockaddr*) &clnt_addr, &clnt_addr_size);
    if(clnt_sock == -1)
      continue;
    else
      puts("new client connected...");
    
    pid=fork();	//创建新进程
    if(pid==-1)
    {
      close(clnt_sock);
      continue;
    }
    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);
      }
      
      close(clnt_sock);
      puts("client disconnected...");
      return 0;
    }
    else	//父进程运行区域
    {
      //调用fork函数后,要将无关的套接字文件描述符关闭掉
      close(clnt_sock);
    }
  }
  
  close(serv_sock);
  return 0;
}

void error_handling(char *message)
{
  fputs(message, stderr);
  fputc('\n', stderr);
  exit(1);
}

//一旦有子进程结束就调用这个函数
void read_childproc(int sig)
{
  int status;
  pid_t id=waitpid(-1, &status, WNOHANG);
  if(WIFEXITED(status))
  {
    printf("remove proc id: %d \n", id);
    printf("child send: %d \n", WEXITSTATUS(status));
  }
}

猜你喜欢

转载自blog.csdn.net/u012411498/article/details/80499512