多进程学习随笔

多进程学习随笔

一、概述:

Linux下一个进程在内存里有三部分的数据:
“代码段”、”堆栈段”和”数据段”。
”代码段”,顾名思义,就是存放了程序代码。
“堆栈段”存放的就是程序的返回地址、程序的参数以及程序的局部变量。
“数据段”则存放程序的全局变量,常数以及动态数据分配的数据空间(比如用new函数分配的空间)。

系统如果同时运行多个相同的程序,它们的“代码段”是相同的,“堆栈段”和“数据段”是不同的(相同的程序,处理的数据不同)。

使用fork函数创建子进程:共用代码段 复制程序的堆栈段与数据段 父子程序独立运行 互不冲突 父进程返回子进程 进程号 子进程返回零
getpid获取当前程序进程号

二、多进程的简单应用

1.socket通信

/*
 * 程序名:book250.cpp,此程序用于演示多进程的socket通信服务端。
 * 作者:C语言技术网(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
 
class CTcpServer
{
public:
  int m_listenfd;   // 服务端用于监听的socket
  int m_clientfd;   // 客户端连上来的socket
 
  CTcpServer();
 
  bool InitServer(int port);  // 初始化服务端
 
  bool Accept();  // 等待客户端的连接
 
  // 向对端发送报文
  int  Send(const void *buf,const int buflen);
  // 接收对端的报文
  int  Recv(void *buf,const int buflen);
 
  void CloseClient();    // 关闭客户端的socket
  void CloseListen();    // 关闭用于监听的socket
 
 ~CTcpServer();
};
 
CTcpServer TcpServer;
 
int main()
{
  // signal(SIGCHLD,SIG_IGN);  // 忽略子进程退出的信号,避免产生僵尸进程
 
  if (TcpServer.InitServer(5051)==false)
  { printf("服务端初始化失败,程序退出。\n"); return -1; }
 
  while (1)
  {
    if (TcpServer.Accept() == false) continue;
 
    if (fork()>0) { TcpServer.CloseClient(); continue; }  // 父进程回到while,继续Accept。
 
    // 子进程负责与客户端进行通信,直到客户端断开连接。
    TcpServer.CloseListen();
 
    printf("客户端已连接。\n");
 
    // 与客户端通信,接收客户端发过来的报文后,回复ok。
    char strbuffer[1024];
 
    while (1)
    {
      memset(strbuffer,0,sizeof(strbuffer));
      if (TcpServer.Recv(strbuffer,sizeof(strbuffer))<=0) break;
      printf("接收:%s\n",strbuffer);
 
      strcpy(strbuffer,"ok");
      if (TcpServer.Send(strbuffer,strlen(strbuffer))<=0) break;
      printf("发送:%s\n",strbuffer);
    }
 
    printf("客户端已断开连接。\n");
 
    return 0;  // 或者exit(0),子进程退出。
  }
}
 
CTcpServer::CTcpServer()
{
  // 构造函数初始化socket
  m_listenfd=m_clientfd=0;
}
 
CTcpServer::~CTcpServer()
{
  if (m_listenfd!=0) close(m_listenfd);  // 析构函数关闭socket
  if (m_clientfd!=0) close(m_clientfd);  // 析构函数关闭socket
}
 
// 初始化服务端的socket,port为通信端口
bool CTcpServer::InitServer(int port)
{
  if (m_listenfd!=0) { close(m_listenfd); m_listenfd=0; }
 
  m_listenfd = socket(AF_INET,SOCK_STREAM,0);  // 创建服务端的socket
 
  // 把服务端用于通信的地址和端口绑定到socket上
  struct sockaddr_in servaddr;    // 服务端地址信息的数据结构
  memset(&servaddr,0,sizeof(servaddr));
  servaddr.sin_family = AF_INET;  // 协议族,在socket编程中只能是AF_INET
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  // 本主机的任意ip地址
  servaddr.sin_port = htons(port);  // 绑定通信端口
  if (bind(m_listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) != 0 )
  { close(m_listenfd); m_listenfd=0; return false; }
 
  // 把socket设置为监听模式
  if (listen(m_listenfd,5) != 0 ) { close(m_listenfd); m_listenfd=0; return false; }
 
  return true;
}
 
bool CTcpServer::Accept()
{
  if ( (m_clientfd=accept(m_listenfd,0,0)) <= 0) return false;
 
  return true;
}
 
int CTcpServer::Send(const void *buf,const int buflen)
{
  return send(m_clientfd,buf,buflen,0);
}
 
int CTcpServer::Recv(void *buf,const int buflen)
{
  return recv(m_clientfd,buf,buflen,0);
}
 
void CTcpServer::CloseClient()    // 关闭客户端的socket
{
  if (m_clientfd!=0) { close(m_clientfd); m_clientfd=0; }
}
 
void CTcpServer::CloseListen()    // 关闭用于监听的socket
{
  if (m_listenfd!=0) { close(m_listenfd); m_listenfd=0; }
}

主进程调用fork函数时 创建子进程
父进程主要负责监听 子进程主要负责通信 两者互不干扰
关闭父进程的connected socket 子进程的 master socket 不影响彼此
2.文件读写

三、僵尸进程
产生:子进程return 或 exit 父进程未回收 子进程结束未被销毁留下僵尸进程
影响:带有标志。继续占用系统资源
消除:
1.子进程退出之前,会向父进程发送一个信号,父进程调用waid函数等待这个信号,只要等到了,就不会产生僵尸进程。
2.signal(SIGCHLD,SIG_IGN); // 忽略子进程退出的信号,避免产生僵尸进程

三、进程交互
1)数据传输:一个进程需要将它的数据发送给另一个进程。
2)共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
3)通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如通知进程退出)。
4)进程控制:一个进程希望控制另一个进程的运行。

进程通信的方式大概分为六种。

1)管道:包括无名管道(pipe)及命名管道(named pipe),无名管道可用于具有父进程和子进程之间的通信。命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。

2)消息队列(message):进程可以向队列中添加消息,其它的进程则可以读取队列中的消息。

3)信号(signal):信号用于通知其它进程有某种事件发生。
4)共享内存(shared memory):多个进程可以访问同一块内存空间。
5)信号量(semaphore):也叫信号灯,用于进程之间对共享资源进行加锁。
6)套接字(socket):可用于不同计算机之间的进程间通信。

参考资料:C语言技术网https://freecplus.net/8bd691add361411d84745282afa7e4fe.html
https://freecplus.net/d95f4eaf18eb46d19b82383519126dec.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值