getmsg系统调用及示例

getmsg 函数详解

  1. 函数介绍

getmsg 是 System V STREAMS 接口中的一个函数,用于从 STREAMS 设备或管道中接收消息。可以把 STREAMS 想象成一个”消息传送带系统”——数据以消息的形式在系统中流动,getmsg 就是从这个传送带上取下消息的工具。

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

STREAMS 是 Unix System V 中的一种模块化 I/O 框架,它允许在数据流中插入处理模块,实现复杂的数据处理。虽然在现代 Linux 系统中 STREAMS 使用较少,但在一些 Unix 系统(如 Solaris)中仍然重要。

getmsg 允许你接收包含控制信息和数据信息的消息,提供了比普通 read 更精细的控制。

getmsg系统调用及示例-CSDN博客

  1. 函数原型
1
2
3
4
#include <stropts.h>

int getmsg(int fildes, struct strbuf *ctlptr, struct strbuf *dataptr, int *flagsp);

  1. 功能

getmsg 函数用于从 STREAMS 文件描述符中接收消息。它可以分别接收消息的控制部分和数据部分,提供了对消息结构的精细控制。

  1. 参数
  • fildes: STREAMS 设备或管道的文件描述符

  • ctlptr: 指向 strbuf 结构体的指针,用于接收控制信息

  • dataptr: 指向 strbuf 结构体的指针,用于接收数据信息

  • flagsp: 指向标志的指针,用于指定接收模式和返回消息类型

  1. strbuf 结构体
1
2
3
4
5
6
struct strbuf {
int maxlen; /* 缓冲区最大长度 */
int len; /* 实际数据长度 */
char *buf; /* 指向缓冲区的指针 */
};

  1. flags 参数说明

输入标志(指定要接收的消息类型):

  • 0: 接收下一条消息(按优先级顺序)

  • RS_HIPRI: 接收下一条高优先级消息

输出标志(返回实际接收到的消息类型):

  • 0: 普通优先级消息

  • RS_HIPRI: 高优先级消息

  1. 返回值
  • 成功: 返回 0 或非负值

  • 失败: 返回 -1,并设置相应的 errno 错误码

特殊返回值:

  • MORECTL: 控制部分还有更多数据

  • MOREDATA: 数据部分还有更多数据

常见错误码:

  • EBADF: fildes 不是有效的文件描述符

  • EINVAL: 参数无效

  • EIO: I/O 错误

  • ENOSTR: fildes 不是 STREAMS 设备

  • ENOSR: 没有足够的 STREAMS 资源

  • EAGAIN: 非阻塞模式下无数据可读

  1. 相似函数或关联函数
  • putmsg: 发送消息到 STREAMS 设备

  • getpmsg: 获取带优先级的消息(更高级的版本)

  • putpmsg: 发送带优先级的消息

  • ioctl: 控制 STREAMS 设备

  • read/write: 普通的文件读写操作

  1. 示例代码

示例1:基础用法 - 简单的消息接收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stropts.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>

// 注意:这个示例在大多数 Linux 系统上可能无法运行
// 因为 Linux 不完全支持 STREAMS

int main() {
int fd;
struct strbuf ctlbuf, databuf;
char ctl_data&#91;256], data_buf&#91;1024];
int flags;

printf("=== getmsg 基础示例 ===\n\n");

// 初始化缓冲区结构
ctlbuf.maxlen = sizeof(ctl_data);
ctlbuf.buf = ctl_data;
ctlbuf.len = 0;

databuf.maxlen = sizeof(data_buf);
databuf.buf = data_buf;
databuf.len = 0;

flags = 0; // 接收普通消息

printf("注意: getmsg 主要用于 STREAMS 系统\n");
printf("在大多数 Linux 系统上可能不可用\n\n");

// 尝试打开一个 STREAMS 设备(示例)
// fd = open("/dev/stream_device", O_RDONLY);
// 由于大多数系统没有 STREAMS 设备,这里只演示结构

printf("控制缓冲区设置:\n");
printf(" 最大长度: %d\n", ctlbuf.maxlen);
printf(" 缓冲区地址: %p\n", (void*)ctlbuf.buf);

printf("数据缓冲区设置:\n");
printf(" 最大长度: %d\n", databuf.maxlen);
printf(" 缓冲区地址: %p\n", (void*)databuf.buf);

printf("标志设置: %d\n", flags);

printf("\n如果在支持 STREAMS 的系统上,可以这样调用:\n");
printf("result = getmsg(fd, &ctlbuf, &databuf, &flags);\n");

return 0;
}

示例2:模拟 STREAMS 消息处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 模拟 STREAMS 消息结构
struct simulated_msg {
int priority; // 消息优先级
int control_len; // 控制数据长度
char control_data&#91;256]; // 控制数据
int data_len; // 数据长度
char data&#91;1024]; // 实际数据
};

// 模拟的 strbuf 结构
struct simulated_strbuf {
int maxlen;
int len;
char *buf;
};

// 模拟的 getmsg 函数
int simulated_getmsg(struct simulated_msg *msg,
struct simulated_strbuf *ctlptr,
struct simulated_strbuf *dataptr,
int *flagsp) {

printf("=== 模拟 getmsg 操作 ===\n");

// 复制控制数据
if (ctlptr && ctlptr->buf) {
int copy_len = (msg->control_len < ctlptr->maxlen) ?
msg->control_len : ctlptr->maxlen;
memcpy(ctlptr->buf, msg->control_data, copy_len);
ctlptr->len = copy_len;
printf("复制控制数据: %d 字节\n", copy_len);
}

// 复制数据
if (dataptr && dataptr->buf) {
int copy_len = (msg->data_len < dataptr->maxlen) ?
msg->data_len : dataptr->maxlen;
memcpy(dataptr->buf, msg->data, copy_len);
dataptr->len = copy_len;
printf("复制数据: %d 字节\n", copy_len);
}

// 设置标志
if (flagsp) {
*flagsp = (msg->priority > 0) ? 1 : 0; // 模拟高优先级标志
}

printf("消息优先级: %s\n",
(msg->priority > 0) ? "高" : "普通");
printf("控制数据长度: %d\n", msg->control_len);
printf("数据长度: %d\n", msg->data_len);

return 0; // 成功
}

// 创建测试消息
struct simulated_msg* create_test_message() {
static struct simulated_msg msg;

msg.priority = 1; // 高优先级
msg.control_len = strlen("CONTROL_INFO") + 1;
strcpy(msg.control_data, "CONTROL_INFO");
msg.data_len = strlen("Hello, STREAMS World!") + 1;
strcpy(msg.data, "Hello, STREAMS World!");

return &msg;
}

int main() {
struct simulated_msg *test_msg;
struct simulated_strbuf ctlbuf, databuf;
char ctl_buffer&#91;256], data_buffer&#91;1024];
int flags;
int result;

printf("=== STREAMS 消息处理模拟 ===\n\n");

// 创建测试消息
test_msg = create_test_message();
printf("创建测试消息完成\n\n");

// 初始化缓冲区
ctlbuf.maxlen = sizeof(ctl_buffer);
ctlbuf.buf = ctl_buffer;
ctlbuf.len = 0;

databuf.maxlen = sizeof(data_buffer);
databuf.buf = data_buffer;
databuf.len = 0;

flags = 0;

// 调用模拟的 getmsg
result = simulated_getmsg(test_msg, &ctlbuf, &databuf, &flags);

if (result == 0) {
printf("\n=== 接收结果 ===\n");
printf("控制数据 (%d 字节): %s\n", ctlbuf.len, ctlbuf.buf);
printf("数据 (%d 字节): %s\n", databuf.len, databuf.buf);
printf("消息标志: %s\n", (flags > 0) ? "高优先级" : "普通优先级");
} else {
printf("接收消息失败\n");
}

return 0;
}

示例3:完整的 STREAMS 消息系统模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// 消息类型定义
#define MSG_NORMAL 0
#define MSG_HIGH_PRIORITY 1
#define MSG_CONTROL 2
#define MSG_DATA 3

// 模拟的 STREAMS 消息队列
struct message_queue {
int count;
struct {
int priority;
int type;
time_t timestamp;
int control_len;
char control_data&#91;128];
int data_len;
char data&#91;512];
} messages&#91;10];
};

// 模拟的 strbuf 结构
struct my_strbuf {
int maxlen;
int len;
char *buf;
};

// 全局消息队列
struct message_queue global_queue = {0};

// 向队列添加消息
int add_message(int priority, int type,
const char *control, const char *data) {
if (global_queue.count >= 10) {
printf("消息队列已满\n");
return -1;
}

int index = global_queue.count++;
global_queue.messages&#91;index].priority = priority;
global_queue.messages&#91;index].type = type;
global_queue.messages&#91;index].timestamp = time(NULL);

if (control) {
global_queue.messages&#91;index].control_len = strlen(control) + 1;
strncpy(global_queue.messages&#91;index].control_data, control, 127);
global_queue.messages&#91;index].control_data&#91;127] = '\0';
} else {
global_queue.messages&#91;index].control_len = 0;
global_queue.messages&#91;index].control_data&#91;0] = '\0';
}

if (data) {
global_queue.messages&#91;index].data_len = strlen(data) + 1;
strncpy(global_queue.messages&#91;index].data, data, 511);
global_queue.messages&#91;index].data&#91;511] = '\0';
} else {
global_queue.messages&#91;index].data_len = 0;
global_queue.messages&#91;index].data&#91;0] = '\0';
}

printf("添加消息: 优先级=%d, 类型=%d, 控制=%s, 数据=%s\n",
priority, type, control ? control : "无", data ? data : "无");

return 0;
}

// 模拟的 getmsg 实现
int my_getmsg(struct my_strbuf *ctlptr,
struct my_strbuf *dataptr,
int *flagsp) {

if (global_queue.count == 0) {
printf("消息队列为空\n");
return -1;
}

// 查找高优先级消息(如果请求)
int msg_index = 0;
if (flagsp && (*flagsp & 1)) { // 模拟 RS_HIPRI
for (int i = 0; i < global_queue.count; i++) {
if (global_queue.messages&#91;i].priority > 0) {
msg_index = i;
break;
}
}
}

// 获取消息
struct message_queue *msg = &global_queue.messages&#91;msg_index];

// 复制控制数据
if (ctlptr && ctlptr->buf) {
int copy_len = (msg->control_len < ctlptr->maxlen) ?
msg->control_len : ctlptr->maxlen;
memcpy(ctlptr->buf, msg->control_data, copy_len);
ctlptr->len = copy_len;
}

// 复制数据
if (dataptr && dataptr->buf) {
int copy_len = (msg->data_len < dataptr->maxlen) ?
msg->data_len : dataptr->maxlen;
memcpy(dataptr->buf, msg->data, copy_len);
dataptr->len = copy_len;
}

// 设置返回标志
if (flagsp) {
*flagsp = (msg->priority > 0) ? 1 : 0; // 高优先级标志
}

// 从队列中移除消息
for (int i = msg_index; i < global_queue.count - 1; i++) {
global_queue.messages&#91;i] = global_queue.messages&#91;i + 1];
}
global_queue.count--;

return 0;
}

// 显示队列状态
void show_queue_status() {
printf("\n=== 消息队列状态 ===\n");
printf("队列中消息数量: %d\n", global_queue.count);

for (int i = 0; i < global_queue.count; i++) {
printf("消息 %d: 优先级=%d, 类型=%d, 时间=%s",
i, global_queue.messages&#91;i].priority,
global_queue.messages&#91;i].type,
ctime(&global_queue.messages&#91;i].timestamp));
printf(" 控制: %s\n", global_queue.messages&#91;i].control_data);
printf(" 数据: %s\n", global_queue.messages&#91;i].data);
}
}

int main() {
struct my_strbuf ctlbuf, databuf;
char ctl_buffer&#91;256], data_buffer&#91;1024];
int flags;
int result;

printf("=== 完整的 STREAMS 消息系统模拟 ===\n\n");

// 初始化缓冲区
ctlbuf.maxlen = sizeof(ctl_buffer);
ctlbuf.buf = ctl_buffer;
ctlbuf.len = 0;

databuf.maxlen = sizeof(data_buffer);
databuf.buf = data_buffer;
databuf.len = 0;

// 添加测试消息
printf("添加测试消息...\n");
add_message(0, MSG_NORMAL, "NORMAL_CTL", "普通消息数据");
add_message(1, MSG_HIGH_PRIORITY, "HIGH_CTL", "高优先级消息");
add_message(0, MSG_DATA, "DATA_CTL", "另一个普通消息");
add_message(1, MSG_CONTROL, "CTRL_CTL", "高优先级控制消息");

show_queue_status();

// 测试接收普通消息
printf("\n--- 测试1: 接收普通消息 ---\n");
flags = 0; // 普通消息
result = my_getmsg(&ctlbuf, &databuf, &flags);

if (result == 0) {
printf("成功接收消息:\n");
printf(" 控制数据: %.*s\n", ctlbuf.len, ctlbuf.buf);
printf(" 数据: %.*s\n", databuf.len, databuf.buf);
printf(" 优先级: %s\n", (flags > 0) ? "高" : "普通");
}

// 测试接收高优先级消息
printf("\n--- 测试2: 接收高优先级消息 ---\n");
flags = 1; // 高优先级消息
result = my_getmsg(&ctlbuf, &databuf, &flags);

if (result == 0) {
printf("成功接收高优先级消息:\n");
printf(" 控制数据: %.*s\n", ctlbuf.len, ctlbuf.buf);
printf(" 数据: %.*s\n", databuf.len, databuf.buf);
printf(" 优先级: %s\n", (flags > 0) ? "高" : "普通");
}

show_queue_status();

printf("\n=== STREAMS 概念说明 ===\n");
printf("STREAMS 是 System V 中的消息传递机制\n");
printf("特点:\n");
printf("1. 消息包含控制部分和数据部分\n");
printf("2. 支持消息优先级\n");
printf("3. 模块化处理架构\n");
printf("4. 主要在 Solaris 等系统中使用\n");
printf("\n在 Linux 中,类似功能可通过以下方式实现:\n");
printf("- Unix 域套接字\n");
printf("- 管道和 FIFO\n");
printf("- netlink 套接字\n");
printf("- D-Bus 消息系统\n");

return 0;
}

编译和运行说明

1
2
3
4
5
6
7
8
9
10
# 编译示例程序
gcc -o getmsg_example1 example1.c
gcc -o getmsg_example2 example2.c
gcc -o getmsg_example3 example3.c

# 运行示例
./getmsg_example1
./getmsg_example2
./getmsg_example3

STREAMS 系统检查

1
2
3
4
5
6
7
8
9
# 检查系统是否支持 STREAMS
ls /usr/include/stropts.h

# 在支持 STREAMS 的系统上编译
gcc -DSTREAMS_AVAILABLE -o getmsg_real example_real.c -lstrmi

# 查看 STREAMS 相关设备
ls /dev/* | grep stream

重要注意事项

系统支持: getmsg 主要在 System V Unix 系统中可用

Linux 限制: 大多数 Linux 系统不完全支持 STREAMS

移植性: 代码可移植性较差

替代方案: Linux 中可以使用其他 IPC 机制

错误处理: 始终检查返回值和 errno

现代 Linux 替代方案

使用 Unix 域套接字

1
2
3
4
5
6
7
8
9
10
#include <sys/socket.h>
#include <sys/un.h>

// 创建 Unix 域套接字进行消息传递
int create_unix_socket(const char *path) {
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
// ... 配置和使用套接字
return sock;
}

使用管道

1
2
3
4
5
6
7
8
#include <unistd.h>

// 创建管道进行进程间通信
int pipe_fd&#91;2];
if (pipe(pipe_fd) == 0) {
// 使用 pipe_fd&#91;0] 读取,pipe_fd&#91;1] 写入
}

实际应用场景

设备驱动: 在某些 Unix 系统中用于设备通信

网络协议: 实现复杂的网络协议栈

系统管理: 系统管理工具的消息传递

模块化处理: 数据流的模块化处理

STREAMS 架构概念

1
2
3
4
5
6
7
8
9
10
11
12
应用程序

STREAMS 接口 (putmsg/getmsg)

流首部 (Stream Head)

模块 1 → 模块 2 → 模块 3

驱动程序 (Driver)

硬件设备

虽然 getmsg 在现代 Linux 系统中使用较少,但了解这个概念有助于理解 Unix 系统的消息传递机制和 STREAMS 架构的设计思想。在实际开发中,建议使用 Linux 原生的 IPC 机制。

data-ad-format="auto" data-full-width-responsive="true">