Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

Препоръка за мултиплатформена socket библиотека (TCP/UDP)?
http://mcu-bg.com/mcu_site/viewtopic.php?f=16&t=13077
Страница 1 от 1

Автор:  gicho [ Пон Юли 21, 2014 10:03 am ]
Заглавие:  Препоръка за мултиплатформена socket библиотека (TCP/UDP)?

По аналогия с темата за GUI библиотеките, търся лека, малка C/C++ библиотека за работа с TCP и UDP сокети.
Изискванията са:
- поддръжка на линукс и win32 (BSD API и Windows sockets)
- да е лека в смисъла да има малко (или никакви) допълнителни зависимости
- да има асинхронно API - т.е. да има някакъв wrapper на select() и threading
- подходящ лиценз за комерсиален софтуер (статично свързан) - т.е. open source QT отпада (примерно MIT или BSD мисля че стават като лиценз)
- производителност не се търси, удобно API е много по-ценно, както и добра документация и примери

Гледах boost::asio и само asio, libevent и няколко други. Засега това най-ми допадна: http://sourceforge.net/projects/socketlibcpp/ но то не поддържа UDP.

Пример за евентуална таргет платформа е openwrt. Т.е. един от тестовите варианти ще е за такава система.

Автор:  miro_atc [ Пон Юли 21, 2014 10:11 am ]
Заглавие:  Re: Препоръка за мултиплатформена socket библиотека (TCP/UDP

а ти ли ще си я портваш?

ако да, то най-доброто решение се казва lwIP ;-)

Автор:  palavrov [ Пон Юли 21, 2014 12:12 pm ]
Заглавие:  Re: Препоръка за мултиплатформена socket библиотека (TCP/UDP

В момента работя с libevent ... става. Подкарах я без проблем под OpenWRT. Ако се спреш на нея ще ти дам едно рамо ако запъне някъде ...

едит: lwIP също става, но там нещо API-то и особенно сорсовете хич не ми паснаха на темперамента :D

Автор:  gicho [ Пон Юли 21, 2014 4:51 pm ]
Заглавие:  Re: Препоръка за мултиплатформена socket библиотека (TCP/UDP

Май ще е libevent-a - ще питам ако възникнат въпроси, благодаря.
Видях че има алтернатива - libev. Имаш ли впечатления?

Автор:  palavrov [ Пон Юли 21, 2014 5:07 pm ]
Заглавие:  Re: Препоръка за мултиплатформена socket библиотека (TCP/UDP

Гледах го и него - изглежда същото като фунцкионалност. Доколкото успях да схвана преди време libevent е имал разни трески за дялане които са провокирали автора на libev да го направи - но това е било преди ... сега libevent се е развил и се ползва в една камара сериозни проекти докато libev е по слабо разпостранено. Та поне за мен везните натежаха заради по голямата юзер база на libevent т.е. повече инфо как се ползва, по стабилно и т.н. Честно казано ползвал съм го само за един проект и откак съм го интегрирал не съм имал никаква причина да го пипам - работи си като пушка.

В момента се заигравам с node.js - за ембедед платформи идва малко тежичко, ама с развитието на хардуера последните няколко години не е кой знае колко голям проблем да се подкара на някоя платка от рода на олимексиното или бигълбоне блек и т.н. - без да имам никаква идея що е то javascript успях за няколко часа да подкарам комуникация със устройството където ползвам libevent - сорса е няма и 100 линии ...

Автор:  gicho [ Пон Юли 21, 2014 10:35 pm ]
Заглавие:  Re: Препоръка за мултиплатформена socket библиотека (TCP/UDP

Точно и node.js ми се въртеше в главата да погледна за тази задача, но само ц/ц++ минава.
Имаш ли някакви референции към приложения или примери с libevent, който да са подходящи за запознаване и "копиране" на идеи?

Автор:  palavrov [ Пон Юли 21, 2014 11:25 pm ]
Заглавие:  Re: Препоръка за мултиплатформена socket библиотека (TCP/UDP

Доколкото помня намерих доста примери с гугле - виж и моя код де, тривиално е:

Код:
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
#include <string.h>

#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/thread.h>

#include <pthread.h>
struct partial_read
{
    uint8_t *   buffer;
    size_t      total;
    size_t      current;
};

inline
void partial_read_init(struct partial_read * const pr, uint8_t * const buffer, const size_t total)
{
    pr->buffer  = buffer;
    pr->total   = total;
    pr->current = 0;
}

inline
bool partial_read_done(struct partial_read const * const pr)
{
    return pr->current == pr->total;
}

inline
size_t partial_read_left(struct partial_read const * const pr)
{
    return pr->total - pr->current;
}

inline
uint8_t * const partial_read_at(struct partial_read const * const pr)
{
    return &pr->buffer[pr->current];
}

inline
void partial_read_append(struct partial_read * const pr, size_t append)
{
    pr->current += append;
}

enum message_type
{   
    MT_PING     = 0x00,
    MT_DELETE   = 0x01,
};

struct message_header
{
    uint8_t type;
};

struct message_delete
{
    uint32_t message_id;
};

static struct message_header    header;
static struct partial_read      header_reader;

static struct message_delete    delete;
static struct partial_read      delete_reader;

static bool bufferevent_input_empty(struct bufferevent *bev)
{
    return evbuffer_get_length(bufferevent_get_input(bev))==0;
}

static
bool bufferevent_partial_read(struct bufferevent *bev, struct partial_read *pr)
{
    while(!partial_read_done(pr))
    {
        if(bufferevent_input_empty(bev))
            return false;

        partial_read_append(pr,
                bufferevent_read(bev, partial_read_at(pr),
                    partial_read_left(pr)));
    }

    return true;
}

static
void communication_readers_init(void)
{
    LOG_ERROR("Preparing to receive new command");

    partial_read_init(&header_reader, (uint8_t *)&header, sizeof(header));
    partial_read_init(&delete_reader, (uint8_t *)&delete, sizeof(delete));
}

static
void read_cb(struct bufferevent *bev, void *ctx)
{
    LOG_ERROR("Receiving data");

    if(!bufferevent_partial_read(bev, &header_reader))
        return;

    switch(header.type)
    {
        case MT_PING:
            LOG_ERROR("PING");
            /* TODO: Add TIMEOUT to close connection if there is no PING for a while */
            break;

        case MT_DELETE:
            if(!bufferevent_partial_read(bev, &delete_reader))
                return;

            LOG_ERROR("DELETE");

            // event_delete(delete.message_id);
            break;

        default:
            LOG_ERROR("Unknown command %02X", header.type);
            event_base_loopexit(bufferevent_get_base(bev), NULL);
            return;
    }

    communication_readers_init();
}

static
struct bufferevent *bev;

static
void event_cb(struct bufferevent *unused_bev, short events, void *ctx)
{
    unused_bev = unused_bev;

    if(events & BEV_EVENT_ERROR)
        LOG_ERRNO("Error from bufferevent");

    LOG_ERROR("Got an event");

    if(events & (BEV_EVENT_ERROR | BEV_EVENT_EOF))
    {
        bufferevent_free(bev); bev=NULL;
    }
}

static
void accept_cb(struct evconnlistener *listener,
        evutil_socket_t fd, struct sockaddr* address, int addr_len,
        void *ctx)
{
    LOG_ERROR("Accepting connection");

    struct event_base *base = evconnlistener_get_base(listener);
    bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

    bufferevent_setcb(bev, read_cb, NULL, event_cb, NULL);
    bufferevent_enable(bev, EV_READ|EV_WRITE);
}

static
void error_cb(struct evconnlistener *listener,
        void *ctx)
{
    struct event_base *base = evconnlistener_get_base(listener);

    LOG_ERRNO("Got an error on listener");

    event_base_loopexit(base, NULL);
}

void communication_run_once(void)
{
    struct  event_base     *base;
    struct  sockaddr_in     sock_addr;
    struct  evconnlistener *listener;

    LOG_ERROR("Starting communication session");

    communication_readers_init();

    /* event base */
    base = event_base_new();
    if(!base) { LOG_ERROR("Couldn't create event base"); return; }

    /* listener address and port */
    sock_addr.sin_family        = AF_INET;
    sock_addr.sin_addr.s_addr   = htonl(0);
    sock_addr.sin_port          = htons(0x5246);

    /* listener */
    listener = evconnlistener_new_bind(base, accept_cb, NULL,
            LEV_OPT_THREADSAFE|LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
            (struct sockaddr*)&sock_addr, sizeof(sock_addr));
    if(listener==NULL) { LOG_ERRNO("Couldn't create listener"); goto free_base; }

    evconnlistener_set_error_cb(listener, error_cb);

    LOG_ERROR("Calling event base dispatch");
    /* dispatch */
    event_base_dispatch(base);

    LOG_ERROR("event base dispatch is done");

    /* exit & clean up */
    if(bev!=NULL) {  bufferevent_free(bev); bev=NULL; }
/* free_listener: */
    evconnlistener_free(listener);
free_base:
    event_base_free(base);
}

void *communication_run(void *ctx)
{
    UNUSED(ctx);

    LOG_ERROR("Starting communication thread");

    for(;;)
        communication_run_once();
}

int main(int argc, char ** argv)
{
    UNUSED(argc); UNUSED(argv);
    pthread_t communication_thread, rfid_thread;

    LOG_ERROR("Starting application");

    evthread_use_pthreads();

    pthread_create(&communication_thread, NULL, communication_run, NULL);
    pthread_create(         &rfid_thread, NULL,          rfid_run, NULL);

    void *status;
    pthread_join(rfid_thread, &status);

    return 0;
}


Дотук е за приемане - малко по сложно е отколкото може да се напише но целта ми беше да е ясно след години кое какво прави ;)
Изпращането на данни по сокета е супер просто:

Код:
void tags_send(const Tags* const tag)
{
    if(bev!=NULL)
        bufferevent_write(bev, &tag->epc, sizeof(tag->epc));
}


Поизрязах кода който няма отношение към libevent - тествано е, работи - може директно да го преправиш до каквото ти трябва ...

Автор:  palavrov [ Пон Юли 21, 2014 11:33 pm ]
Заглавие:  Re: Препоръка за мултиплатформена socket библиотека (TCP/UDP

И виж само за куриоз node.js кода който комуникира колко е по кратък:
Код:
var dissolve = require("dissolve");
var net = require("net");

var rfidAntenna = function (id, url) {

    var self = this;

    var log_id = "Antenna #"+id+"("+url+") ";

    var parser = dissolve().loop(function(end) {
        this.buffer("epc",32).tap(function(){
            this.push(this.vars);
            this.vars = {};
        });
    });

    parser.on("readable", function() {
        var e;
        while( e = parser.read()) {
            self.emit("read", {
                date: new Date(),
                epc:e.epc });
        }
    });

    var socket = net.Socket();
    var socket_connected = false;
    var need_reconnect = false;

    var timer = null;

    var reconnect = function() {
        need_reconnect = false;

        if(timer) {
            clearInterval(timer);
            timer = null;
        }

        socket = net.Socket();
        socket.setKeepAlive(true);
        socket.connect(0x5246, url);

        socket.on("data", function(d){
            parser.write(d);
        });

        socket.on("end", function() {
            need_reconnect = true;
            if(socket_connected) {
                console.log(log_id+"socket closed - reconnecting ...");
                socket_connected = false;
            }
        });

        socket.on("error", function() {
            need_reconnect = true;
            if(socket_connected) {
                console.log(log_id+"socket error - reconnecting ...");
                socket_connected = false;
            }
        });

        socket.on("connect", function() {
            console.log(log_id+"socket connected");
            socket_connected = true;
        });

        /* emulate keepalive once per second */
        timer = setInterval(function() {
            if(need_reconnect) {
                reconnect();
            } else if(socket_connected) {
                socket.write("00","hex");
            }
        }, 1000);
    };

    reconnect();
}

rfidAntenna.prototype = Object.create(require('events').EventEmitter.prototype);
module.exports = rfidAntenna;


Това което не ми харсва е, че след време най вероятно ще се затрудня да го разбера какво точно прави и защо работи - бързо писане, трудна поддръжка след време ... виж на C е по бавно писане, но пък по евтина поддръжка по нататък ...

Автор:  gicho [ Вто Юли 22, 2014 7:47 am ]
Заглавие:  Re: Препоръка за мултиплатформена socket библиотека (TCP/UDP

Благодаря! Изглежда идеално за начало.

Автор:  [ Съб Авг 02, 2014 1:29 pm ]
Заглавие:  Re: Препоръка за мултиплатформена socket библиотека (TCP/UDP

Qt :-) , не е малка, нито пък лека, но каквото съм написал на Qt го пускам без преработка на Windows/Linux. Сега вече има и Android, но още не съм го пробвал.

Автор:  gicho [ Вто Авг 05, 2014 6:27 pm ]
Заглавие:  Re: Препоръка за мултиплатформена socket библиотека (TCP/UDP

Много е голямо qt-то - само core-а е няколко мегабайта. На някой от устройствата го има качено, но на други го няма и не мога да го качвам.
Мисля че лиценза на open source варианта не позволява статично линкване, иначе това би било идеалния вариант?

Страница 1 от 1 Часовете са според зоната UTC + 1 час [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/