В чём разница между Berkeley socket и POSIX pipe?

«В чём разница между Berkeley socket и POSIX pipe?» — вопрос из категории Linux и ОС, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Berkeley Sockets (BSD Sockets) — это API для сетевого взаимодействия, позволяющее программам обмениваться данными по сети с использованием различных протоколов (TCP, UDP, RAW). POSIX Pipe — это механизм межпроцессного взаимодействия (IPC) для однонаправленной передачи потока байтов между процессами на одной машине.

Ключевые отличия:

  1. Область применения: Sockets предназначены для сетевой коммуникации (локальной или удалённой), pipes — только для локального IPC.
  2. Направленность: Сокеты по умолчанию двунаправленные (full-duplex). Именованные каналы (FIFO) также могут быть двунаправленными, но обычный (анонимный) pipe, созданный pipe(), — строго однонаправленный.
  3. Адресация: Сокеты используют комбинацию IP-адреса и порта. Pipes используют файловые дескрипторы или путь в файловой системе (для именованных каналов).
  4. Производительность: Pipes, как правило, быстрее для локального обмена, так как данные не проходят через сетевой стек ОС.

Пример создания и использования pipe в C++ (POSIX):

#include <unistd.h>
#include <iostream>

int main() {
    int fd[2];
    char buffer[20];

    if (pipe(fd) == -1) { /* обработка ошибки */ }

    pid_t pid = fork();
    if (pid == 0) { // Дочерний процесс
        close(fd[0]); // Закрываем конец для чтения
        write(fd[1], "Hello from pipe!", 16);
        close(fd[1]);
    } else { // Родительский процесс
        close(fd[1]); // Закрываем конец для записи
        read(fd[0], buffer, 16);
        buffer[16] = '';
        std::cout << "Received: " << buffer << std::endl;
        close(fd[0]);
    }
    return 0;
}

Пример создания TCP-сокета в C++ (Berkeley Sockets):

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

int create_client_socket(const char* server_ip, int port) {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) { /* обработка ошибки */ }

    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    inet_pton(AF_INET, server_ip, &serv_addr.sin_addr);

    if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
        close(sockfd);
        return -1;
    }
    return sockfd; // Сокет готов для send()/recv()
}

Выбор инструмента: Используйте pipes для быстрой коммуникации между родственными процессами на одном хосте. Используйте sockets, когда требуется сетевое взаимодействие или коммуникация между неродственными процессами.