pl-sem/sem8/pipe-example-1.c
2023-08-18 01:08:53 +03:00

180 lines
4.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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;
}