[LINUX] Programmation asynchrone avec libev # 3

Voici un exemple de client HTTPS avec SSL utilisant libev.

Ajoutez le chemin ou le lien suivant vers xcode:

Chemin du fichier d'en-tête Chemin du fichier de bibliothèque Bibliothèques dépendantes
usr/local/opt/openssl/include /usr/local/opt/openssl/lib libcrypto.a、libssl.a

Je bloque la connexion. S'il n'y a pas de problème de communication, le html de la première page de google sera affiché sur la console.

Veuillez consulter # 1 pour l'installation de libev.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string>
#include <ev.h>
#include <iostream>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#define SOCKET int
#define SD_BOTH SHUT_WR

#include <openssl/ssl.h>
#include <openssl/err.h>

#define READ_BUF_SIZE 4096
#define BUF_SIZE 4097
#define PORT 443

SSL *_ssl;

void close_socket(SOCKET socket, SSL_CTX *_ctx, SSL *_ssl){
    
    // SSL/Arrêtez la connexion TLS.
    SSL_shutdown(_ssl);
    SSL_free(_ssl);
    
    ::shutdown(socket, SD_BOTH);
    ::close(socket);
    
    SSL_CTX_free(_ctx);
    ERR_free_strings();
    
}

int get_error(){
    return errno;
}

//Préparer SSL
SSL_CTX * ssl_setup(){
    
    //Initialisation de la bibliothèque SSL.
    SSL_library_init();
    
    //Préparation à la chaîne de l'erreur.
    SSL_load_error_strings();
    
    //Initialisation du contexte global.
    const SSL_METHOD *meth = SSLv23_method();
    
    return SSL_CTX_new(meth);
}

//Connexion TCP.
SOCKET tcp_connect(const char* host){
    
    struct hostent *hp;
    struct sockaddr_in addr;
    SOCKET _socket;
    
    if (!(hp = gethostbyname(host))){
        return -1;
    }
    memset(&addr, 0, sizeof(addr));
    addr.sin_addr = *(struct in_addr*)hp->h_addr_list[0];
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    
    if ((_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))<0){
        return -1;
    }
    if (connect(_socket, (struct sockaddr *)&addr, sizeof(addr))<0){
        return -1;
    }
    
    return _socket;
}


static void io_cb (EV_P_ ev_io *w, int revents)
{
    char buf[BUF_SIZE] = { 0 };
    char* p = buf;
    int r = SSL_read(_ssl, p, READ_BUF_SIZE);
    
    if(r > 0){
        std::cout << p;
    }
    
    
    //Commentez ce qui suit pour terminer avec un délai d'attente.
    
    // I/Dissocier O de la boucle.
    //ev_io_stop (EV_A_ w);
    
    //Briser la boucle des événements.
    //ev_unloop (EV_A_ EVUNLOOP_ALL);
}

static void timeout_cb (EV_P_ ev_timer *w, int revents)
{
    std::cout << "timeout\n";

    //Arrêtez le chronomètre.
    ev_timer_stop (EV_A_ w);
    
    //Briser la boucle des événements.
    ev_unloop (EV_A_ EVUNLOOP_ONE);
}

int main(int argc, const char * argv[])
{
    
    std::string host = "www.google.co.jp";
    
    SOCKET _socket = tcp_connect(host.c_str());
    
    SSL_CTX *_ctx = ssl_setup();
    
    //Créer un objet de session SSL.
    _ssl = SSL_new(_ctx);
    
    //Associer avec socket.
    SSL_set_fd(_ssl, _socket);

    //Connexion SSL.
    int error = 0;
    if (SSL_connect(_ssl) <= 0){
        error = get_error();
        ::shutdown(_socket, SD_BOTH);
        close_socket(_socket, _ctx, _ssl);
        return 0;
    }
    
    //Défini sur non bloquant.
    int flag = fcntl(_socket, F_GETFL, 0);
    fcntl(_socket, F_SETFL, flag | O_NONBLOCK);
    
    
    //Créer une boucle d'événements.
    struct ev_loop *loop = ev_loop_new (0);

    // I/Ô objet de montre.
    ev_io io_watcher;
    
    // I/Pour les objets O watch
    //Associer des rappels aux FD avec des types d'événements.
    ev_io_init (&io_watcher, io_cb, _socket, EV_READ);
    
    // I/Associer une boucle d'événement à un objet O watch.
    ev_io_start (loop, &io_watcher);


    //Créer un objet minuterie.
    ev_timer timeout_watcher;
    
    //Associer un rappel à un objet timer et spécifier un timeout.
    ev_timer_init (&timeout_watcher, timeout_cb, 20, 0.);
    
    //Associer une boucle d'événements à un objet timer.
    ev_timer_start (loop, &timeout_watcher);
    
    
    std::string str = "GET / HTTP/1.1\r\nHost: " + host;
    str = str + "\r\n\r\n";
    int w = SSL_write(_ssl, str.c_str(), static_cast<int>(str.length()));
    
    
    std::cout << "write count" << w << "\n";
    
    //Début de boucle.
    ev_loop (loop, 0);

    //Si vous ne voulez pas bloquer.
    //ev_loop (loop, EVLOOP_NONBLOCK);

    
    std::cout << "end\n";
    
    //Supprimer la boucle d'événements créée
    ev_loop_destroy(loop);
    
    close_socket(_socket, _ctx, _ssl);
    
    return 0;
}

Compiler avec gcc

gcc -o test test.cpp -lev -I/usr/local/Cellar/libev/4.15/include/ -L/usr/local/Cellar/libev/4.15/lib/ -L/usr/local/opt/openssl/lib -I/usr/local/opt/openssl/include -lcrypto -lssl -lstdc++

Recommended Posts

Programmation asynchrone avec libev # 2
Programmation asynchrone avec libev
Programmation asynchrone avec libev # 3
3. 3. Programmation IA avec Python
Programmation compétitive avec python
Programmation Shader avec pyOpenGL
Programmation linéaire avec PuLP
Programmation avec Python Flask
Programmation avec Python et Tkinter
Essayez la programmation GUI avec Hy
Jeu éducatif de programmation avec SenseHAT
Programmation réseau avec Python Scapy
[Python] Programmation orientée objet apprise avec Pokemon
Programmation facile Python + OpenCV avec Canopy
[Python] Requête asynchrone avec async / await
Programmation pour les humains avec un __repr__ bien défini
Programmation GUI à l'aide de kivy ~ Partie 4 Divers boutons ~
Compréhension complète de la programmation asynchrone Python
Faites de la programmation embarquée avec un développement piloté par les tests avec googletest
Programmation sonore avec Go (super niveau d'introduction)
Ce que vous pouvez faire avec des compétences en programmation