操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

时间:2023-03-09 03:54:49
操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

进程通信(信号量、匿名管道、命名管道、Socket)

具体的概念就没必要说了,参考以下链接。

Source Code:

1. 信号量(生产者消费者问题)

 #include <iostream>
#include <Windows.h>
#include <process.h>
#include <vector>
using namespace std; #define STD _stdcall //被调用者负责清栈
int BufferSize; //缓冲区大小 CRITICAL_SECTION CR; //临界区
HANDLE Empty = NULL; //信号量:空闲缓冲区
HANDLE Full = NULL; //信号量:满缓冲区
vector<int>Buffer; //缓冲区 /*生产者线程*/
DWORD STD Producer(void *lp)
{
while(true)//自旋测试
{
//等待空缓冲区:P(empty)
WaitForSingleObject(Full, INFINITE);//一直等待
//进入缓冲区P(mutex)
EnterCriticalSection(&CR);
//生产数据
int s = rand()%;
Buffer.push_back(s);
cout << "Producer produces an element : " << s <<endl;
//退出缓冲区V(mutex)
LeaveCriticalSection(&CR);
//增加满缓冲区V(full)
ReleaseSemaphore(Empty, , NULL);
//睡一会儿
Sleep();
}
} /*消费者线程*/
DWORD STD Consumer(void *lp)
{
while(true)//自旋测试
{
//等待满缓冲区:P(empty)
WaitForSingleObject(Empty, INFINITE);//一直等待
//进入缓冲区P(mutex)
EnterCriticalSection(&CR);
//取出数据
int r = Buffer[Buffer.size()-];
Buffer.pop_back();
cout << " Consumer consumes an element : " << r <<endl;
//退出缓冲区V(mutex)
LeaveCriticalSection(&CR);
//增加空缓冲区V(full)
ReleaseSemaphore(Full, , NULL);
//睡一会儿
Sleep();
}
} int main()
{
cout << "Input the number of BufferSize : "; cin >> BufferSize;
//创建信号量
Empty = CreateSemaphore(NULL, , BufferSize, NULL);
Full = CreateSemaphore(NULL, BufferSize, BufferSize,NULL); //初始化临界区
InitializeCriticalSection(&CR); int pNum, cNum;
cout << "Input the number of Producer(Max:10) : "; cin >> pNum;
cout << "Input the number of Consumer(Max:10) : "; cin >> cNum; //创建线程
int i;
HANDLE handle[];
for(i=; i<pNum; i++)
{
handle[i] = CreateThread(, , &Producer, , , );
}
for(i=pNum; i<pNum+cNum; i++)
{
handle[i] = CreateThread(, , &Consumer, , , );
} //回收线程
WaitForMultipleObjects(pNum+cNum, handle, true, INFINITE); //释放线程
for(i=; i<pNum+cNum; i++)
{
CloseHandle(handle[]);
} //释放缓冲区
DeleteCriticalSection(&CR);
return ;
}

结果:

操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

2. 匿名管道(本地父进程与子进程通信)

原理:

操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

源码:

 /*
*匿名管道:父子进程通信
*date : 2018/12/3
*author : yocichen
*status : Done
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int main()
{
//pipe1 p to s, pipe2 s to p
int fd_1[], fd_2[]; if(pipe(fd_1)< || pipe(fd_2)<)//fail to create pipe
{
printf("Fail to create the pipe.\n");
return -;
} char buf[];//
const char *temp; //child
int fork_result = fork();
if(fork_result == )
{
close(fd_1[]);//close read port
close(fd_2[]);//close write port //read message
read(fd_1[], buf, sizeof(buf));//read message from father port
printf("\nChild : receive a message from pipe1: %s\n", buf); //write message
temp = "Hi, my parent, I love you too.";
write(fd_2[], temp, strlen(temp));//child write message to pipe2
} else
{
close(fd_2[]);
close(fd_1[]); //write message
temp = "My child, I love you.";
write(fd_1[], temp, strlen(temp));//parent write message to pipe1 //read message
read(fd_2[], buf, sizeof(buf));//read message from pipe2
printf("\nParent : receive a message from pipe2: %s\n", buf);
}
return ;
}

(注意:该匿名管道程序为Linux系统开发,注意运行环境,windows下使用CodeBlocks可以运行)

操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

3.命名管道

原理:

操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

源码:

 #include <windows.h>
#include <stdio.h>
#include <stdlib.h> int main()
{
//创建命名管道
HANDLE namedPipe = CreateNamedPipeA("\\\\.\\pipe\\testName", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, , , , , NULL); //校验状态
if(namedPipe == INVALID_HANDLE_VALUE)
{
printf("Server: Fail to create named pipe.\n");
}
else
{
printf("Server: Succeed to create pipe.\n");
} OVERLAPPED op;
ZeroMemory(&op, sizeof(OVERLAPPED)); //创建事件对象
op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //等待连接
bool b = ConnectNamedPipe(namedPipe, &op);
printf("Server: Listen...\n"); int status = WaitForSingleObject(op.hEvent, INFINITE);
//连接成功
if(status == )
{
printf("Server: Succeed to connect.\n");
}
else
{
printf("Server: Fail to connect.\n");
} //通信
char buf[] = "来玩个猜数游戏吧!\n";
DWORD wp;
WriteFile(namedPipe, buf, strlen(buf), &wp, NULL); int ans = rand()%+;
while(status == )
{
ZeroMemory(buf, );
ReadFile(namedPipe, buf, , &wp, NULL);
printf("收到:%s\n", buf); if(int(buf[] - '') < ans)
{
WriteFile(namedPipe, "小了,再猜一次!\n", strlen("小了,再猜一次!\n"), &wp, NULL);
}
else if((buf[]-'') > ans)
{
WriteFile(namedPipe, "大了,再猜一次!\n", strlen("大了,再猜一次!\n"), &wp, NULL);
}
else
{
WriteFile(namedPipe, "猜对了!\n", strlen("小了,再猜一次!\n"), &wp, NULL);
break;
} if(buf[] == '')
{
printf("客户已退出!\n");
break;
}
} //通信结束
DisconnectNamedPipe(namedPipe);
return ;
}

Server

 #include <windows.h>
#include <stdio.h>
#include <stdlib.h> int main()
{
//检查管道是否存在
bool b = WaitNamedPipeA("\\\\.\\pipe\\testName", ); //打开管道
HANDLE hFile = CreateFileA("\\\\.\\pipe\\testName", GENERIC_READ | GENERIC_WRITE, , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); //是否连接成功
if(b == || hFile == INVALID_HANDLE_VALUE)
{
printf("Client: fail to connect.\n");
return ;
}
else
{
printf("Client: Succeed to connect.\n");
} //通信
char buf[];
ZeroMemory(buf, );
DWORD rp;
ReadFile(hFile, buf, , &rp, NULL);//读取
printf(buf); while(true)
{
printf("输入数字:");
scanf("%s", buf);
WriteFile(hFile, buf, strlen(buf), &rp, NULL); while(ReadFile(hFile, buf, , &rp, NULL) == true)
{
printf("Server: ");
printf(buf);
break;
}
} CloseHandle(hFile);
return ;
}

Client

操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

4.Socket网络进程通信

原理:

操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

源码:

 /*注意头文件顺序*/
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "ws2_32.lib") //引入动态链接库 int main()
{
WORD ws_version = MAKEWORD(, ); //指定Winsock version
WSADATA wsaData; //WSA 函数的参数 /*初始化winsock*/
WSAStartup(ws_version, &wsaData); /*socket*/
SOCKET s_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN addr_server;
addr_server.sin_family = AF_INET; //协议
addr_server.sin_port = htons(); //端口
addr_server.sin_addr.s_addr = htonl(INADDR_ANY); //IP:任意IP /*bind*/
int bind_status;
bind_status = bind(s_server, (SOCKADDR*)&addr_server, sizeof(SOCKADDR));
if(bind_status == SOCKET_ERROR)
{
printf("bind error : fail to bind! \n");
}
else
{
printf("bind successfully!\n");
} /*listen*/
listen(s_server, );//max=5
printf("listening ... \n"); SOCKADDR_IN addr_client; //存储client地址信息
int len = sizeof(SOCKADDR);
int count = ; //统计客户数目
SOCKET s_client; //连接的socket char buf[];
while(true)
{
printf("等待客户端连接...\n");
/*accept*/
s_client = accept(s_server, (SOCKADDR*)&addr_client, &len);
if(s_client == INVALID_SOCKET)
{
printf("Accept error : fail to accept client! ");
}
else//连接成功
{
count++;
printf("\nAccept successfully!\n"); printf("---------------------------------------------\n");
printf(" 编号:%d \n", count);
printf(" Port:%d\n", ntohs(addr_client.sin_port));
printf(" IP:%s\n", inet_ntoa(addr_client.sin_addr));//inet_ntoa(SOCKADDR.in_addr)网络地址转换为IP int recv_status = recv(s_client, buf, , );
if(recv_status > )
{
printf("收到:");
buf[recv_status] = 0x00;//截断
printf(buf);
printf("\n---------------------------------------------\n");
}
const char *sendData = "你好!客户端!我是服务器";
send(s_client, sendData, strlen(sendData), );
closesocket(s_client);
}
} closesocket(s_server); //关闭socket
WSACleanup(); return ;
}

Server

 #include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib") //引入动态链接库
#define SERVER_IP "192.168.31.102" //客户端IP
using namespace std; int main()
{
WORD ws_version = MAKEWORD(, ); //指定Winsock version
WSADATA wsaData; //WSA 函数的参数 /*初始化winsock*/
WSAStartup(ws_version, &wsaData); while(true)
{
/*socket*/
SOCKET s_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN addr_server;
addr_server.sin_family = AF_INET; //协议
addr_server.sin_port = htons(); //端口
addr_server.sin_addr.s_addr = inet_addr(SERVER_IP); char buf[];
int send_status, recv_status; /*Connect*/
int cnct_status = connect(s_client, (SOCKADDR*)&addr_server, sizeof(SOCKADDR));
if(cnct_status == )//连接成功
{
printf("\nConnecting... done\n"); //向服务端发送消息
printf("输入发送信息:");
scanf("%s", buf);
send_status = send(s_client, buf, , );
if(send_status == SOCKET_ERROR)//发送失败
{
printf("send error!\n");
}
else
{
printf("发送:%s\n", buf);
//接受服务端消息
recv_status = recv(s_client, buf, , );
buf[recv_status] = 0x00;//截断
printf("收到:%s\n", buf);
}
}
else
{
printf("Test:fail to connect server! \n");
}
closesocket(s_client);
} WSACleanup(); return ;
}

Client

操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

操作系统-进程通信(信号量、匿名管道、命名管道、Socket)