180 lines
4.3 KiB
C
180 lines
4.3 KiB
C
/* pipe-example-1.c */
|
||
|
||
#include <stdint.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
#include <sys/wait.h>
|
||
|
||
enum
|
||
{
|
||
MSG_STRING = 1,
|
||
MSG_END
|
||
};
|
||
|
||
enum
|
||
{
|
||
MESSAGE_MAGIC = 0xAFAF, // magic signature value
|
||
MAX_MESSAGE_LEN = 4096 // maximum message length
|
||
};
|
||
|
||
struct __attribute__((packed)) message_header
|
||
{
|
||
uint16_t magic; // magic signature
|
||
uint16_t type; // type of the message
|
||
uint16_t data_len; // length of data
|
||
};
|
||
|
||
enum
|
||
{
|
||
// maximum data length
|
||
MAX_MESSAGE_DATA_LEN = MAX_MESSAGE_LEN - sizeof(struct message_header)
|
||
};
|
||
|
||
struct __attribute__((packed)) message
|
||
{
|
||
struct message_header header;
|
||
// payload
|
||
uint8_t data[MAX_MESSAGE_DATA_LEN];
|
||
};
|
||
|
||
struct message simple_message(uint16_t type)
|
||
{
|
||
return (struct message) {(struct message_header) {MESSAGE_MAGIC, type, 0}, 0};
|
||
}
|
||
|
||
struct message string_message(const char *str)
|
||
{
|
||
struct message msg = (struct message) {(struct message_header) {MESSAGE_MAGIC, MSG_STRING, strlen(str + 1)}, 0};
|
||
strcpy(msg.data, str);
|
||
return msg;
|
||
}
|
||
|
||
int send(int fd, const struct message *msg)
|
||
{
|
||
/* Check if the input data is not empty */
|
||
if (fd < 0 || msg == NULL)
|
||
return -1;
|
||
|
||
/* Calculate the message size to send */
|
||
int msg_size = sizeof(struct message_header) + msg->header.data_len;
|
||
|
||
/* Check if message payload size is valid */
|
||
if (msg->header.data_len > MAX_MESSAGE_DATA_LEN)
|
||
return -1;
|
||
|
||
/* Write data to the output pipe (we assume it is ready) */
|
||
if (write(fd, msg, msg_size) != msg_size)
|
||
return -2;
|
||
|
||
return 0;
|
||
}
|
||
|
||
int receive(int fd, struct message *msg)
|
||
{
|
||
/* Check if the input data is not empty */
|
||
if (fd < 0 || msg == NULL)
|
||
return -1;
|
||
|
||
/* Try to read header */
|
||
int msg_size = read(fd, &msg->header, sizeof(struct message_header));
|
||
if (msg_size == 0)
|
||
return 0;
|
||
|
||
/* Check header magic */
|
||
if (msg->header.magic != MESSAGE_MAGIC)
|
||
return -2;
|
||
|
||
/* Check if message has payload */
|
||
if (msg->header.data_len > MAX_MESSAGE_DATA_LEN)
|
||
return -2;
|
||
if (msg->header.data_len > 0)
|
||
msg_size += read(fd, &msg->data, msg->header.data_len);
|
||
|
||
/* Return number of bytes read */
|
||
return msg_size;
|
||
}
|
||
|
||
|
||
int main() {
|
||
// Создадим два конвейера
|
||
int pipes[2][2];
|
||
pipe(pipes[0]);
|
||
pipe(pipes[1]);
|
||
|
||
// Создадим дочерний процесс
|
||
pid_t pid = fork();
|
||
if (pid == 0) {
|
||
// Сохраним нужные дескпиторы конвейеров
|
||
int to_parent_pipe = pipes[1][1];
|
||
int from_parent_pipe = pipes[0][0];
|
||
|
||
// И закроем ненужные
|
||
close(pipes[1][0]);
|
||
close(pipes[0][1]);
|
||
|
||
// Будем читать строки и отправлять их сообщениями
|
||
char str[MAX_MESSAGE_DATA_LEN];
|
||
for (;;)
|
||
{
|
||
// Прочитаем строку
|
||
if (fgets(str, MAX_MESSAGE_DATA_LEN, stdin) == NULL)
|
||
return 0;
|
||
if (strlen(str) <= 1)
|
||
break;
|
||
|
||
// И отпавим её родителю
|
||
struct message msg = string_message(str);
|
||
send(to_parent_pipe, &msg);
|
||
}
|
||
|
||
// Отправим сообщение о завершении ввода
|
||
struct message msg = simple_message(MSG_END);
|
||
send(to_parent_pipe, &msg);
|
||
|
||
// Закроем дескпиторы
|
||
close(to_parent_pipe);
|
||
close(from_parent_pipe);
|
||
|
||
return 0;
|
||
}
|
||
|
||
// Далее выполняется только родительский поток
|
||
// Сохраним нужные дескпиторы конвейеров
|
||
int from_child_pipe = pipes[1][0];
|
||
int to_child_pipe = pipes[0][1];
|
||
|
||
// И закроем ненужные
|
||
close(pipes[1][1]);
|
||
close(pipes[0][0]);
|
||
|
||
// Будем ждать, пока ребенок не пришлет сообщение
|
||
struct message msg;
|
||
while (1)
|
||
{
|
||
int ret;
|
||
while (ret = receive(from_child_pipe, &msg) == 0)
|
||
;
|
||
if (ret < 0)
|
||
return 1;
|
||
|
||
// Если это строка - выведем её
|
||
if (msg.header.type == MSG_STRING)
|
||
printf("Recieved string from child: %s\n", (char *)msg.data);
|
||
// Если конец ввода - прервемся
|
||
else if (msg.header.type == MSG_END)
|
||
{
|
||
printf("Recieved END from child\n");
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Дождемся завершения ребенка
|
||
waitpid(pid, NULL, 0);
|
||
|
||
// Закроем дескпиторы
|
||
close(from_child_pipe);
|
||
close(to_child_pipe);
|
||
|
||
return 0;
|
||
}
|