- 浏览: 327502 次
- 性别:
- 来自: 北京
最新评论
-
lshhjxlj:
不错,赞一个
[翻译]Swing组件集合的事件处理(一) -
mxjisp:
...
Linux下的汇编开发 -
arust:
CSDN 的开发团队技术稀烂的
Linux杂记
CD数据库程序
现在我们可以使用我们在这一章所了解的IPC工具来修改我们的CD数据库程序。
我们可以使用三种IPC工具的多种不同组,但是因为我们需要传送的信息很少,直接使用消息队列实现请求的传递是一个很明显的选择。
如果我们需要传递的数据量很大,我们可以考虑使用共享内存传递实际的数据,并且使用信号量或是消息来传递一个标记通知其他的进程在共享内存中有数据可用。
消息队列接口解决我们了在第11章所遇到的问题,即当数据传递时我们需要两个进程使得管道打开。使用消息队列可以使得一个进程将消息放入队列,尽管这个进程是当前队列的唯一用户。
我们需要考虑的一个重要决定就是将答案返回给客户。一个简单的选择就是使得一个队列用于服务器而且每个客户有一个队列。如果有大量的并发客户,由于需要大量的消息队列就会引起问题。通过使用消息中的消息ID域,我们可以使得所有的用户使用一个队列,并且通过在消息中使用客户端进程ID来将响应发送给指定的客户端进程。从而每一个客户可以接收只属于他自己的消息,而将其他客户的消息留在队列中。
要转换我们的CD程序来使用IPC工具,我们只需要替换pipe_imp.c文件。在下面的部分,我们将会描述替换文件ipc_imp.c的原则部分。
试验--修改服务器函数
1 首先,我们包含正确的头文件,声明消息队列键值,并且定义一个保存我们消息数据的结构:
#include “cd_data.h”
#include “cliserv.h”
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define SERVER_MQUEUE 1234
#define CLIENT_MQUEUE 4321
struct msg_passed {
long int msg_key; /* used for client pid */
message_db_t real_message;
};
2 两个全局变量保存由msgget函数所返回的两个队列标识符:
static int serv_qid = -1;
static int cli_qid = -1;
3 我们使得服务器负责创建两个消息队列:
int server_starting()
{
#if DEBUG_TRACE
printf(“%d :- server_starting()\n”, getpid());
#endif
serv_qid = msgget((key_t)SERVER_MQUEUE, 0666 | IPC_CREAT);
if (serv_qid == -1) return(0);
cli_qid = msgget((key_t)CLIENT_MQUEUE, 0666 | IPC_CREAT);
if (cli_qid == -1) return(0);
return(1);
}
4 服务器同时负责退出时的清理工作。当服务器结束时,我们设置我们的全局变量为非法值。这就会捕获服务器尝试在调用server_ending之后发送消息的bug。
void server_ending()
{
#if DEBUG_TRACE
printf(“%d :- server_ending()\n”, getpid());
#endif
(void)msgctl(serv_qid, IPC_RMID, 0);
(void)msgctl(cli_qid, IPC_RMID, 0);
serv_qid = -1;
cli_qid = -1;
}
5 服务器read函数由队列中读取一条任意的消息,并且返回消息的数据部分。
int read_request_from_client(message_db_t *rec_ptr)
{
struct msg_passed my_msg;
#if DEBUG_TRACE
printf(“%d :- read_request_from_client()\n”, getpid());
#endif
if (msgrcv(serv_qid, (void *)&my_msg, sizeof(*rec_ptr), 0, 0) == -1) {
return(0);
}
*rec_ptr = my_msg.real_message;
return(1);
}
6 使用存储在清求中标识消息的客户进程ID来发送响应:
int send_resp_to_client(const message_db_t mess_to_send)
{
struct msg_passed my_msg;
#if DEBUG_TRACE
printf(“%d :- send_resp_to_client()\n”, getpid());
#endif
my_msg.real_message = mess_to_send;
my_msg.msg_key = mess_to_send.client_pid;
if (msgsnd(cli_qid, (void *)&my_msg, sizeof(mess_to_send), 0) == -1) {
return(0);
}
return(1);
}
试验--修改客户端函数
1 当客户端启动时,他需要发现服务器与客户端队列标识符。客户端并不创建队列。如果服务器没有运行,这个函数就会失败,因为消息队列并不存在。
int client_starting()
{
#if DEBUG_TRACE
printf(“%d :- client_starting\n”, getpid());
#endif
serv_qid = msgget((key_t)SERVER_MQUEUE, 0666);
if (serv_qid == -1) return(0);
cli_qid = msgget((key_t)CLIENT_MQUEUE, 0666);
if (cli_qid == -1) return(0);
return(1);
}
2 与服务器一样,当客户端结束时,我们设置我们的全局变量为非法值。这将会捕获当客户端尝试在调用client_ending之后发送消息的bug。
void client_ending()
{
#if DEBUG_TRACE
printf(“%d :- client_ending()\n”, getpid());
#endif
serv_qid = -1;
cli_qid = -1;
}
3 要向服务器发送消息,我们在我们的结构中存储数据。注意,我们必须设置消息键值。因为0作为键值是非法的,保留键值未定义就意味着他可以使用一个随机值,所以如果这个值恰好为0时函数就会失败。
int send_mess_to_server(message_db_t mess_to_send)
{
struct msg_passed my_msg;
#if DEBUG_TRACE
printf(“%d :- send_mess_to_server()\n”, getpid());
#endif
my_msg.real_message = mess_to_send;
my_msg.msg_key = mess_to_send.client_pid;
if (msgsnd(serv_qid, (void *)&my_msg, sizeof(mess_to_send), 0) == -1) {
perror(“Message send failed”);
return(0);
}
return(1);
}
4 当客户端服务器接收消息时,他会使用其进程ID来接收只发送给他的消息,而忽略其他进程的消息。
int read_resp_from_server(message_db_t *rec_ptr)
{
struct msg_passed my_msg;
#if DEBUG_TRACE
printf(“%d :- read_resp_from_server()\n”, getpid());
#endif
if (msgrcv(cli_qid, (void *)&my_msg, sizeof(*rec_ptr), getpid(), 0) == -1) {
return(0);
}
*rec_ptr = my_msg.real_message;
return(1);
}
5 要获得与pipe_imp.c的完全兼容,我们需要定义另外四个函数。然而,在我们的新程序中,这个函数是空的。当使用管道时他们所实现的操作也不再需要了。
int start_resp_to_client(const message_db_t mess_to_send)
{
return(1);
}
void end_resp_to_client(void)
{
}
int start_resp_from_server(void)
{
return(1);
}
void end_resp_from_server(void)
{
}
此程序到消息队列的转换演示了IPC消息队列的强大。我们需要更少的函数,而我们所需要要比以前的实现少得多。
IPC状态函数
尽管X/Open并没有要求,大多数的Linux提供了一个命令集合来允许命令行访问IPC信息,并且清理无关联的IPC工具。这就是ipcs与ipcrm命令,当我们开发程序时,这是非常有用的。
编写糟糕的程序或是因为某些原因失败的程序会遗留其IPC资源。这会使得新的程序调用失败,因为程序期望以一个干净的系统开始,但是却发现一些遗留的资源。状态(ipcs)与清除(ipcrm)命令提供了一个检测与清除IPC遗留资源的一种方法。
信号量
要检测系统中信息量的状态,可以使用ipcs -s命令。如果存在一些信号量,输出就会有如下的形式:
$ ./ipcs -s
——— Semaphore Arrays ————
semid owner perms nsems status
768 rick 666 1
我们可以使用ipcrm命令来移除由程序偶然留下的信号量。要删除前面的信号量,可以使用下面的命令:
$ ./ipcrm -s 768
一些较老的Linux系统使用一些略微不同的语法:
$ ./ipcrm sem 768
但是这种风格不再推荐使用。查看我们系统的手册页来确定在我们的系统上是哪种格式。
共享内存
与信号量类似,许多系统提供了命令行程序用于访问共享内存的详细信息。命令为ipcs -m与ipcrm -m <id>。
如下面的例子输出:
$ ipcs -m
——— Shared Memory Segments ————
shmid owner perms bytes nattch status
384 rick 666 4096 2
这显示一个4KB的共享内存段与两个进程相关联。
ipcrm -m <id>命令可以移除共享内存。当一个程序清理共享内存失败时,这会十分有用。
消息队列
对于消息队列的命令为ipcs -q与ipcrm -q <id>。
如下面的例子输出:
$ ipcs -q
——— Message Queues ————
msqid owner perms used-bytes messages
384 rick 666 2048 2
这显示了在消息队列中有两个消息,共计2048字节。
ipcrm -q <id>命令可以移除消息队列。
总结
在这一章,我们了解了首次在UNIX Systme V.2中广泛使用并且在Linux中可用的三种进程间交互工具。他们是信号量,共享内存与消息队列。我们了解了他们所提供的高级功能以及如何提供这些功能,一旦理解了这些函数,他们就会为需要进程间通信的程序提供强大的解决方案。
发表评论
-
Linux杂记
2009-09-04 23:28 1070最近一段时间似乎国内 ... -
关于Beginning Linux Programming 3ed
2009-08-25 19:00 1136关于<Beginning Linux Progr ... -
进程间通信之消息队列
2009-08-24 23:33 1395消息队列 现在我们来讨论第三种也是最后一种System ... -
进程间通信之共享内存
2009-08-23 11:51 2039共享内存 共享内存是第二种IPC工具。他允许两个无关的进 ... -
Linux进程间通信之信号量
2009-08-22 08:43 1924第14章 信号量,共享内存与消息队列 在这一章,我们将会 ... -
fglrx 9.8与kernel 2.6.30
2009-08-20 12:11 861Linux Kernel 2.6.30的发布已是很早之前的事情 ... -
进程间通信(九)
2009-08-15 10:49 1003管道 下面是管道实现文件,pipe_imp.c,其中有客 ... -
进程间通信(八)
2009-08-11 23:25 859搜索数据库 在CD关键字上的搜索比较复杂。函数的用户希望 ... -
进程间通信(七)
2009-08-09 10:11 917CD数据库程序 现在我们已经了解了我们可以如何使用有名管 ... -
进程间通信(六)
2009-08-08 10:08 1199读取与写入FIFO 使用O_NONBLOCK模式会影响作 ... -
进程间通信(五)
2009-08-04 12:20 1457有名管道:FIFO 到目前为止,我们只是可以在两个相关的 ... -
进程间通信(四)
2009-08-03 12:37 977父子进程 我们的pipe调用探索的下一步就是使得子进程是 ... -
进程间通信(三)
2009-08-02 09:04 1069管道调用 我们已经了解了高层的popen函数,现在我们继 ... -
进程间通信(二)
2009-08-01 13:00 1349传递更多的数据 到目 ... -
进程间通信(一)
2009-07-31 15:41 1489第13章 进程间通信:管道 在第11章,我们了解了使用信 ... -
POSIX线程-(六)
2009-07-23 18:24 1912线程属性-调度 下面我们来看一下我们也许希望改变的第二个 ... -
POSIX线程-(四)
2009-07-19 15:06 1296使用互斥同步 在多线程程序中同步访问的另一个方法就是使用 ... -
POSIX线程-(五)
2009-07-21 18:02 1418线程属性 当我们第一次了解线程时,我们并没有讨论线程属性 ... -
POSIX线程(三)
2009-07-08 18:21 1282并发执行 下面我们将要编写一个检测两个线程是否并发执行的 ... -
POSIX线程(二)
2009-07-05 10:32 1691第一个线程程序 有一 ...
相关推荐
操作系统实验报告(LINUX进程间通信)是操作系统课程的一部分,涵盖了Linux进程间通信的原理和应用,包括消息队列、C/S结构等内容。下面将对这些知识点进行详细的解释。 一、消息队列 消息队列是Linux进程间通信的...
此外,本文还对多进程程序设计方案进行了实践,例如使用 fork 函数形成同原有进程基本上具有一致性的进程,并且使用信号量和等待函数来实现进程间的通信和同步。通过这些实践,可以更好的理解和掌握多进程程序设计的...
通过以上实验,学生能够全面地理解和掌握Linux操作系统的基本命令、编程技巧、进程间通信、内存管理、设备驱动以及网络编程等多个方面的知识和技术,为进一步深入研究和应用Linux操作系统奠定坚实的基础。
4. 学习使用POSIX/UNIX系统调用,对进程进行管理和完成进程之间的通信,例如使用信号和管道进行进程间通信。 5. 理解并发程序中的同步问题。 6. 锻炼在团队成员之间的交流与合作能力。 ysh解释程序的重要特征: 1....
- **进程间通信(IPC)**:可能涉及管道(pipe)、消息队列、共享内存等通信方式。 - **信号处理**:学习如何使用`signal()`函数注册信号处理函数,以及常见的信号如SIGINT(中断),SIGTERM(终止)等。 3. **...
这本书涵盖了从基础到高级的多个关键领域,包括Linux操作系统原理、C编程、进程控制、多线程编程、进程间通信、网络编程以及设备驱动开发等。每个章节都配有高清的doc文档,以便读者深入理解并实践。此外,教程还...
Android 是一个专门针对移动设备的软件集,它包括一个操作系统,中间件和一些重要的应用程序。 Beta 版 的 Android SDK 提供了在 Android 平台上使用 JaVa 语言进行 Android 应用开发必须的工具和 API 接口。 特性 ...
**管道通信**是操作系统中一种重要的进程间通信方式。本实验旨在帮助学生深入理解管道通信的工作原理及其在UNIX/Linux环境下的具体应用。 #### 二、设计任务详解 ##### 1. 熟悉UNIX命令与编辑器 - **目标**: 掌握...
- 进程通信——信号的使用:使用信号进行进程间通信。 - 防止僵死进程:解决僵尸进程问题。 #### 五、用户图形界面设计 - **QT应用编程**: - QT基础:了解QT框架的基本概念。 - 编写GUI应用程序:使用QT ...
第8章“进程间通信”讲解了Linux中不同进程如何共享数据和协调工作,包括管道、消息队列、共享内存、信号量和套接字等多种通信机制,是实现多进程协同工作的关键。 第9章“多线程编程”涉及线程的概念、创建和管理...
QtDBus 是用于实现基于 DBus 协议的进程间通信 (IPC) 的组件。尽管 QtDBus 默认支持 Unix 类操作系统,但 Windows 用户同样希望能够在 Windows 平台上使用这一功能。本文将详细介绍如何在 Windows 环境下构建 QtDBus...
本章将介绍`ps`(查看进程状态)、`kill`(发送信号给进程)、`nohup`(让进程在后台持续运行)等命令,以及进程间通信(IPC)的基本原理。 **第6章 网络编程** 嵌入式Linux系统常常需要处理网络通信。本章将讲解套...
Android专用驱动系统篇介绍了Logger日志驱动程序、Binder进程间通信驱动程序以及Ashmem匿名共享内存驱动程序;Android应用程序框架篇从组件、进程、消息以及安装四个维度对Android应用程序的框架进行了深入的剖析。...
**第七章LinuxApp07-ProcessControlling.pdf**:这章可能涉及进程管理,包括进程创建(fork、exec系列函数)、进程间通信(管道、消息队列、共享内存等)、信号处理等,这些都是多任务操作系统中理解和控制程序行为...
《嵌入式Linux应用程序开发详解02-Linux基础命令》主要涵盖了Linux系统中的一些核心概念和常用命令,这些对于在嵌入式系统中进行应用程序开发至关重要。本章旨在帮助读者熟练掌握Linux的基础操作,以便更好地利用...