目錄
一、管道通信
二、匿名管道
1. 匿名管道通信
2. 匿名管道設(shè)計
三、命名管道
comm.hpp
client.cc
serve.cc
一、管道通信
進程通信
數(shù)據(jù)傳輸:一個進程需要將它的數(shù)據(jù)發(fā)送給另一個進程
資源共享:多個進程之間共享同樣的資源
通知事件:一個進程向另一個(一組)進程發(fā)送信息,通知它們發(fā)生了某種事件
進程控制:一個進程完全控制另一個進程的執(zhí)行,如debug
通信本質(zhì)
OS直接或間接給通信雙方提供內(nèi)存空間
通信的進程雙方,能夠讀取到一份公共資源
管道文件是內(nèi)存級文件
管道創(chuàng)建
?
管道讀寫端
- 如果管道沒有了數(shù)據(jù),讀端在讀,默認會阻塞等待正在讀取的進程
- 管道是固定大小的空間,寫端寫滿的時候,會阻塞等待讀端讀取
- 寫端關(guān)閉,讀端在讀,則讀端讀完管道數(shù)據(jù)也關(guān)閉
- 讀端關(guān)閉,寫端在寫,OS終止寫端
int main()
{
int fds[2];
int n = pipe(fds);
assert(n == 0);
cout << "fds[0]: " << fds[0] << endl;
cout << "fds[1]: " << fds[1] << endl;
return 0;
}
管道可用于父子、兄弟、祖孫進程之間通信
二、匿名管道
1. 匿名管道通信
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <cassert>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int main()
{
// 1. 創(chuàng)建管道文件,打開讀寫端
int fds[2];
int n = pipe(fds);
assert(n == 0);
// 2. fork()
pid_t id = fork();
if (id == 0)
{
//子進程通信代碼
close(fds[0]); //關(guān)閉讀端
const char* s = "我是子進程,我正在給你發(fā)消息";
int cnt = 0;
while (true)
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "child->parent say: %s[%d][%d]", s, cnt++, getpid());
write(fds[1], buffer, strlen(buffer));
sleep(1);
}
exit(0);
}
//父進程通信代碼
close(fds[1]); //關(guān)閉寫端
while (true)
{
char buffer[1024];
ssize_t s = read(fds[0], buffer, sizeof(buffer) - 1);
if (s > 0)
buffer[s] = 0;
cout << "Get Message# " << getpid() << buffer << " | my pid: " << getpid() << endl;
//父進程沒有sleep
}
n = waitpid(id, nullptr, 0);
assert(n == id);
return 0;
}
2. 匿名管道設(shè)計
- 將任務(wù)存入存入任務(wù)表vector中,將子進程存入信息存入subs容器中
- 父進程隨機將任務(wù)碼發(fā)給5個子進程,子進程讀取任務(wù)碼完成任務(wù)(父進程為寫端,子進程為讀端),若子進程未讀取任務(wù),則進行阻塞等待
- 通過隨機數(shù)分配任務(wù)給隨機子進程,讓子進程負載均衡
代碼設(shè)計流程:
- 建立任務(wù)表,建立子進程及和子進程通信的信道
- 父進程控制子進程,進行任務(wù)分配
- 回收子進程信息
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <cassert>
#include <cstring>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>
using namespace std;
#define MakeSeed() srand((unsigned int)time(nullptr) ^ getpid())
#define PROCESS_NUM 5
#define TASK_NUM 10
typedef void(*func_t)();
void DownLoad()
{
cout << getpid() << " DownLoad Task" << endl;
sleep(1);
}
void IOTask()
{
cout << getpid() << " IO Task" << endl;
sleep(1);
}
void FlushTask()
{
cout << getpid() << " Flush Task" << endl;
}
void LoadTaskFunc(vector<func_t>& funcMap)
{
funcMap.push_back(DownLoad);
funcMap.push_back(IOTask);
funcMap.push_back(FlushTask);
}
/
class subEp
{
public:
subEp(pid_t subID, int writeFd)
: _subID(subID), _writeFd(writeFd)
{
char nameBuffer[1024];
snprintf(nameBuffer, sizeof(nameBuffer), "process-%d[pid(%d)-fd(%d)]", num++, subID, _writeFd);
_name = nameBuffer;
}
static int num;
string _name;
pid_t _subID;
int _writeFd;
};
int subEp::num = 0;
// 讀取
int RecvTask(int readFd)
{
int code = 0;
ssize_t s = read(readFd, &code, sizeof(code));
if (s == sizeof(int))
return code;
else if (s <= 0)
return -1;
else
return 0;
}
void CreateSubProcess(vector<subEp>& subs, vector<func_t>& funcMap)
{
vector<int> deleteFd;
for (int i = 0; i < PROCESS_NUM; ++i)
{
int fds[2];
int n = pipe(fds);
assert(n == 0);
(void) n;
pid_t id = fork();
if (id == 0)
{
//建立一對一管道
for (int i = 0; i < deleteFd.size(); ++i)
close(deleteFd[i]);
//子進程處理任務(wù)
close(fds[1]);
while (true)
{
// 1. 獲取任務(wù)碼,如果沒收到任務(wù)碼,則阻塞等待
int commandCode = RecvTask(fds[0]);
// 2. 執(zhí)行任務(wù)
if (commandCode >= 0 && commandCode < funcMap.size())
funcMap[commandCode]();
else
break;
}
exit(0);
}
close(fds[0]);
subEp sub(id, fds[1]);
subs.push_back(sub);
deleteFd.push_back(fds[1]);
}
}
void SendTask(const subEp& process, int taskNum)
{
cout << "send task num " << taskNum << " to " << process._name << endl;
int n = write(process._writeFd, &taskNum, sizeof(taskNum));
assert(n == sizeof(int));
(void)n;
}
void LoadBlanceContrl(const vector<subEp>& subs, vector<func_t>& funcMap, int count)
{
int procNum = subs.size();
int taskNum = funcMap.size();
while (count--)
{
int subIDx = rand() % procNum;
int taskIDx = rand() % taskNum;
SendTask(subs[subIDx], taskIDx);
sleep(1);
}
for (int i = 0; i < procNum; ++i)
close(subs[i]._writeFd);
}
void WaitProcess(vector<subEp>& subs)
{
int procNum = subs.size();
for (int i = 0; i < procNum; ++i)
{
waitpid(subs[i]._subID, nullptr, 0);
cout << "wait sub process success ... " << subs[i]._subID << endl;
}
}
int main()
{
MakeSeed();
// 1. 建立子進程并建立和子進程通信的信道
// [子進程id,wfd]
vector<func_t> funcMap;
LoadTaskFunc(funcMap);
vector<subEp> subs;
CreateSubProcess(subs, funcMap);
// 2. 父進程控制子進程
LoadBlanceContrl(subs, funcMap, TASK_NUM);
// 3. 回收子進程信息
WaitProcess(subs);
return 0;
}
三、命名管道
讓不同進程打開指定名稱(路徑+文件名)的同一個文件
文章來源:http://www.zghlxwxcb.cn/news/detail-547059.html
comm.hpp
#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <string>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <unistd.h>
#include <fcntl.h>
#include <fstream>
#define NAMED_PIPE "/root/test/pipe/named_pipe"
bool CreateFilo(const std::string& path)
{
umask(0);
int n = mkfifo(path.c_str(), 0666);
if (n == 0)
{
return true;
}
else
{
std::cout << "errno: " << errno << "err string: " << strerror(errno) << std::endl;
return false;
}
}
void RemoveFifo(const std::string& path)
{
int n = unlink(path.c_str());
assert(n == 0); //意料之中用assert判斷,意料之外用 if else
(void)n;
}
client.cc
#include "comm.hpp"
int main()
{
std::cout << "client begin" << std::endl;
int wfd = open(NAMED_PIPE, O_WRONLY, 0666);
std::cout << "client end" << std::endl;
if (wfd < 0)
exit(1);
//write
char buffer[1024];
while (true)
{
std::cout << "please say# ";
fgets(buffer, sizeof(buffer), stdin);
if (strlen(buffer) > 0)
buffer[strlen(buffer) - 1] = 0;
ssize_t n = write(wfd, buffer, strlen(buffer));
assert(n == strlen(buffer));
(void)n;
}
close(wfd);
return 0;
}
serve.cc
#include "comm.hpp"
int main()
{
bool r = CreateFilo(NAMED_PIPE);
assert(r);
(void)r;
std::cout << "serve begin" << std::endl;
int rfd = open(NAMED_PIPE, O_RDONLY);
std::cout << "serve end" << std::endl;
if (rfd < 0)
exit(1);
//read
char buffer[1024];
while (true)
{
ssize_t s = read(rfd, buffer, sizeof(buffer) - 1);
if (s > 0)
{
std::cout << "client->serve# " << buffer << std::endl;
}
else
{
perror("read");
exit(1);
}
}
close(rfd);
RemoveFifo(NAMED_PIPE);
return 0;
}
文章來源地址http://www.zghlxwxcb.cn/news/detail-547059.html
到了這里,關(guān)于【Linux后端服務(wù)器開發(fā)】管道設(shè)計的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!