Как закодировать клиент сокетов на основе epoll на C

Все примеры, которые я могу найти в Интернете, - это серверы. Я хочу создать базовый поисковый робот с использованием epoll. Поэтому мне нужен базовый пример клиента, чтобы начать работу.

Когда я говорю «базовый», я действительно имею в виду полный пример, демонстрирующий множественные соединения с отправкой и получением данных на действующие веб-хосты. Например, простой запрос HEAD и ответ на него.

Как вы думаете, что отличает клиента от сервера? epoll() не знает разницы. Вы используете его таким же образом, когда у вас есть несколько сокетов, на которых вы слушаете ввод.

Barmar 10.08.2018 02:56
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
1
9 044
1

Ответы 1

Вот пример кода c для клиентского сокета с epoll.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 22
#define SERVER "127.0.0.1"
#define MAXBUF 1024
#define MAX_EPOLL_EVENTS 64

int main() {
    int sockfd;
    struct sockaddr_in dest;
    char buffer[MAXBUF];
    struct epoll_event events[MAX_EPOLL_EVENTS];
    int i, num_ready;

    /*---Open socket for streaming---*/
    if ( (sockfd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0)) < 0 ) {
        perror("Socket");
        exit(errno);
    }

    /*---Add socket to epoll---*/
    int epfd = epoll_create(1);
    struct epoll_event event;
    event.events = EPOLLIN; // Cann append "|EPOLLOUT" for write events as well
    event.data.fd = sockfd;
    epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);

    /*---Initialize server address/port struct---*/
    bzero(&dest, sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(PORT);
    if ( inet_pton(AF_INET, SERVER, &dest.sin_addr.s_addr) == 0 ) {
        perror(SERVER);
        exit(errno);
    }

    /*---Connect to server---*/
    if ( connect(sockfd, (struct sockaddr*)&dest, sizeof(dest)) != 0 ) {
        if (errno != EINPROGRESS) {
            perror("Connect ");
            exit(errno);
        }
    }

    /*---Wait for socket connect to complete---*/
    num_ready = epoll_wait(epfd, events, MAX_EPOLL_EVENTS, 1000/*timeout*/);
    for(i = 0; i < num_ready; i++) {
        if (events[i].events & EPOLLIN) {
            printf("Socket %d connected\n", events[i].data.fd);
        }
    }

    /*---Wait for data---*/
    num_ready = epoll_wait(epfd, events, MAX_EPOLL_EVENTS, 1000/*timeout*/);
    for(i = 0; i < num_ready; i++) {
        if (events[i].events & EPOLLIN) {
            printf("Socket %d got some data\n", events[i].data.fd);
            bzero(buffer, MAXBUF);
            recv(sockfd, buffer, sizeof(buffer), 0);
            printf("Received: %s", buffer);
        }
    }

    close(sockfd);
    return 0;
}

Это версия с синхронизацией по фронту или по уровню?

James Read 10.08.2018 05:02

По умолчанию epoll запускается по уровню. Чтобы он вел себя как срабатывающий по фронту, необходимо установить или установить бит "| EPOLLET" в флаге событий (event.events)

Murli 10.08.2018 05:35

Как можно расширить этот код для обработки 10 000 одновременных подключений для файла со 100 000 IP-адресов?

James Read 10.08.2018 05:59

Когда вы имеете дело со 100K одноранговыми узлами, вам нужно иметь дело не только с интерфейсом epoll. Например, сбои подключения, повторные попытки, частичное чтение, медленные одноранговые узлы, ошибки синтаксического анализа HTTP и т. д. Есть много разных способов его разработки. Обычно я начинаю с одного потока «подключения» для подключения к одноранговым узлам и пула потоков «чтения» для чтения данных из сокетов. Имейте IPC-подобные трубы для передачи подключенного сокета fd от потока "соединение" к потоку "чтения". Я уверен, что, когда вы начнете, таких сценариев будет гораздо больше. Всего наилучшего!!

Murli 10.08.2018 06:55

Я имею в виду, должен ли я вызывать epoll_ctl (epfd, EPOLL_CTL_ADD, sockfd, & event) для каждого sockfd или я могу передать массив sockfd и просто вызвать его один раз? В вашем примере неясно, как он будет работать с несколькими сокетами.

James Read 10.08.2018 08:26

epoll_ctl с EPOLL_CTL_ADD следует вызывать один раз для каждого сокета. И когда вызывается epoll_wait, он будет отслеживать все добавленные сокеты и возвращать только те FD, у которых есть некоторые события для использования.

Murli 10.08.2018 10:52

Зачем вам здесь два epoll_wait? Один для проверки полноты соединения, а другой - для проверки каких-либо данных.

q0987 18.10.2020 21:17

@ q0987 Первый epoll_wait предназначен для завершения установления соединения с сокетом, а второй epoll_wait - ждать данных.

Murli 19.10.2020 07:47

Другие вопросы по теме