rudp

本文深入探讨了可靠用户数据报协议(RUDP)的概念,分析其与TCP和UDP的区别,并详细介绍了如何在C++中利用struct、thread、socket等技术实现RUDP的基本功能,包括数据包的顺序传递和重传机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

lock.h:

#ifndef __LOCK_H__
#define __LOCK_H__


#include <pthread.h>

class MutexLocker
{
public:
    MutexLocker();
    ~MutexLocker();

    void lock();
    void unlock();

private:
    pthread_mutex_t m_locker;
};

class RWLocker
{
public:
    RWLocker();
    ~RWLocker();

    void rdlock();
    void wrlock();
    void unlock();

private:
    pthread_rwlock_t m_locker;
};


#endif

lock.cpp:

#include <cstdio>
#include <cstdlib>
#include <error.h>
#include <cstring>
#include "lock.h"

MutexLocker::MutexLocker()
{
    int error_no = 0;
    if (0 != (error_no = pthread_mutex_init(&m_locker, NULL)))
    {
        printf("pthread_mutex_init error: %s\n", strerror(error_no));
        exit(1);
    }
}

MutexLocker::~MutexLocker()
{
    int error_no = 0;
    if (0 != (error_no = pthread_mutex_destroy(&m_locker)))
    {
        printf("pthread_mutex_destroy error: %s\n", strerror(error_no));
        exit(1);
    }
}

void MutexLocker::lock()
{
    int error_no = 0;
    if (0 != (error_no = pthread_mutex_lock(&m_locker)))
    {
        printf("pthread_mutex_lock error: %s\n", strerror(error_no));
        exit(1);
    }
}

void MutexLocker::unlock()
{
    int error_no = 0;
    if (0 != (error_no = pthread_mutex_unlock(&m_locker)))
    {
        printf("pthread_mutex_unlock error: %s\n", strerror(error_no));
        exit(1);
    }
}

RWLocker::RWLocker()
{
    int error_no = 0;
    if (0 != (error_no = pthread_rwlock_init(&m_locker, NULL)))
    {
        printf("pthread_rwlock_init error: %s\n", strerror(error_no));
        exit(1);
    }
}

RWLocker::~RWLocker()
{
    int error_no = 0;
    if (0 != (error_no = pthread_rwlock_destroy(&m_locker)))
    {
        printf("pthread_rwlock_destroy error: %s\n", strerror(error_no));
        exit(1);
    }
}

void RWLocker::rdlock()
{
    int error_no = 0;
    if (0 != (error_no = pthread_rwlock_rdlock(&m_locker)))
    {
        printf("pthread_rwlock_rdlock error: %s\n", strerror(error_no));
        exit(1);
    }
}

void RWLocker::wrlock()
{
    int error_no = 0;
    if (0 != (error_no = pthread_rwlock_wrlock(&m_locker)))
    {
        printf("pthread_rwlock_wrlock error: %s\n", strerror(error_no));
        exit(1);
    }
}

void RWLocker::unlock()
{
    int error_no = 0;
    if (0 != (error_no = pthread_rwlock_unlock(&m_locker)))
    {
        printf("pthread_rwlock_unlock error: %s\n", strerror(error_no));
        exit(1);
    }
}

types.h:

#ifndef __TYPES_H__
#define __TYPES_H__


typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;

typedef uint32_t seq_type;
typedef uint32_t time_type;


#endif

common.h:

#ifndef __COMMON_H__
#define __COMMON_H__


#include "types.h"

time_type getcurtime();
void big2little(void * object, int size);


#endif

common.cpp:

#include <cstdio>
#include <sys/time.h>
#include "common.h"

time_type getcurtime()
{
    static struct timeval base;
    static bool first_time = true;

    if (first_time)
    {
        gettimeofday(&base, NULL);
        first_time = false;
    }

    struct timeval curtime;
    gettimeofday(&curtime, NULL);

    time_type delta = 0;
    if (curtime.tv_usec < base.tv_usec)
    {
        delta = (1000000 + curtime.tv_usec - base.tv_usec) / 1000;
        --curtime.tv_sec;
    }
    else
    {
        delta = (curtime.tv_usec - base.tv_usec) / 1000;
    }
    delta += (curtime.tv_sec - base.tv_sec) * 1000;

    return(delta);
}

void big2little(void * object, int size)
{
    static union
    {
        uint16_t us;
        unsigned char uc[sizeof(uint16_t)];
    } un;

    un.us = 0x0001;

    if (0x00 == un.uc[0])
    {
        char * ptr = (char *)object;
        for (int i = 0; i < size / 2; ++i)
        {
            char temp = ptr[i];
            ptr[i] = ptr[size - 1 - i];
            ptr[size - 1 - i] = temp;
        }
    }
}

nodes.hpp:

#ifndef __NODES_H__
#define __NODES_H__


#include <cassert>
#include <iostream>
using std::min;
using std::max;

#include "types.h"
#include "lock.h"

template <typename NodeType>
class NodePool
{
public:
    NodePool(NodePool<typename NodeType::InnerNode> * p) : first_node(NULL), inner_pool(p)
    {

    }

    ~NodePool()
    {
        locker.lock();
        NodeType * ptr = first_node;
        while (NULL != ptr)
        {
            first_node = first_node->next;
            delete ptr;
            ptr = first_node;
        }
        locker.unlock();
    }

    NodeType * get_node()
    {
        NodeType * ptr = NULL;

        locker.lock();
        if (NULL != first_node)
        {
            ptr = first_node;
            first_node = first_node->next;
            if (NULL != first_node)
            {
                first_node->prev = NULL;
            }
            ptr->prev = NULL;
            ptr->next = NULL;
        }
        else
        {
            ptr = new NodeType(inner_pool);
        }
        locker.unlock();

        return(ptr);
    }

    void put_node(NodeType * node)
    {
        put_node(node, node);
    }

    void put_node(NodeType * head, NodeType * tail)
    {
        assert(NULL != head && NULL != tail);

        locker.lock();
        tail->next = first_node;
        if (NULL != first_node)
        {
            first_node->prev = tail;
        }
        first_node = head;
        first_node->prev = NULL;
        locker.unlock();
    }

private:
    NodeType * first_node;
    NodePool<typename NodeType::InnerNode> * inner_pool;
    MutexLocker locker;
};

template <typename NodeType>
struct NodeLink
{
    typedef NodePool<NodeType> PoolType;

    NodeType * head;
    NodeType * tail;
    PoolType * pool;
    uint16_t size;

    NodeLink(PoolType * p)
     : head(NULL), tail(NULL), pool(p), size(0)
    {
        assert(NULL != pool);
    }

    ~NodeLink()
    {
        clear();
    }

    bool push_after(NodeType * loc, NodeType * node)
    {
        if (NULL == loc)
        {
            assert(false);
            return(false);
        }

        if (NULL == node)
        {
            assert(false);
            return(false);
        }

        node->prev = loc;
        node->next = loc->next;
        if (NULL != loc->next)
        {
            loc->next->prev = node;
        }
        else
        {
            tail = node;
        }
        loc->next = node;

        ++size;

        return(true);
    }

    bool push_front(NodeType * node)
    {
        if (NULL == node)
        {
            assert(false);
            return(false);
        }

        node->prev = NULL;
        node->next = head;
        if (NULL != head)
        {
            head->prev = node;
        }
        else
        {
            tail = node;
        }
        head = node;

        ++size;

        return(true);
    }

    bool push_back(NodeType * node)
    {
        if (NULL == node)
        {
            assert(false);
            return(false);
        }

        node->prev = tail;
        node->next = NULL;
        if (NULL == tail)
        {
            head = node;
        }
        else
        {
            tail->next = node;
        }
        tail = node;

        ++size;

        return(true);
    }

    bool push_back(NodeLink<NodeType> & node_list)
    {
        if (NULL == node_list.head)
        {
            assert(false);
            return(false);
        }

        node_list.head->prev = tail;
        if (NULL == tail)
        {
            head = node_list.head;
        }
        else
        {
            tail->next = node_list.head;
        }
        tail = node_list.tail;

        size += node_list.size;

        node_list.head = node_list.tail = NULL;
        node_list.size = 0;

        return(true);
    }

    bool erase(NodeType * node)
    {
        assert(NULL != pool);

        if (NULL == node)
        {
            assert(false);
            return(false);
        }

        if (NULL != node->prev)
        {
            node->prev->next = node->next;
        }
        else
        {
            head = node->next;
        }
        if (NULL != node->next)
        {
            node->next->prev = node->prev;
        }
        else
        {
            tail = node->prev;
        }

        node->clear();
        pool->put_node(node);

        --size;

        return(true);
    }

    void clear()
    {
        assert(NULL != pool);

        NodeType * node = head;
        while (NULL != node)
        {
            node->clear();
            node = node->next;
        }

        if (NULL != head)
        {
            pool->put_node(head, tail);
        }
        head = tail = NULL;
        size = 0;
    }
};

typedef struct TimeInfo
{
    uint8_t index;
    time_type time;
    struct TimeInfo * prev;
    struct TimeInfo * next;

    typedef void InnerNode;

    TimeInfo(NodePool<void> * p) : index(0), time(0), prev(NULL), next(NULL)
    {

    }

    ~TimeInfo()
    {
        clear();
    }

    void clear()
    {

    }
} TimeNode;

typedef struct SeqInfo
{
    seq_type front_sequence;
    seq_type behind_sequence;
    NodeLink<TimeNode> time_list;
    struct SeqInfo * prev;
    struct SeqInfo * next;

    typedef TimeNode InnerNode;

    SeqInfo(NodePool<TimeNode> * p)
     : front_sequence(0), behind_sequence(0),
       time_list(p), prev(NULL), next(NULL)
    {

    }

    ~SeqInfo()
    {
        clear();
    }

    int compare(const struct SeqInfo * other) const
    {
        assert(NULL != other);

        if (front_sequence < other->front_sequence)
        {
            assert(behind_sequence <= other->front_sequence);
            return(-1);
        }
        else if (front_sequence > other->front_sequence)
        {
            assert(front_sequence >= other->behind_sequence);
            return(1);
        }
        else /* if (front_sequence == other->front_sequence) */
        {
            assert(behind_sequence == other->behind_sequence);
            return(0);
        }
    }

    TimeNode * find_time_node(uint8_t index)
    {
        assert(0 != index);

        TimeNode * node = time_list.head;
        while (NULL != node)
        {
            if (index < node->index)
            {
                assert(false);
                return(NULL);
            }
            else if (index > node->index)
            {
                node = node->next;
            }
            else
            {
                return(node);
            }
        }
        return(NULL);
    }

    void clear()
    {
        time_list.clear();
    }
} SeqNode;

typedef struct SendDataInfo
{
    enum { send_node_block_size = 16384 };
    seq_type first_sequence;
    uint16_t using_size;
    uint16_t blank_size;
    NodeLink<SeqNode> seq_list;
    struct SendDataInfo * prev;
    struct SendDataInfo * next;
    unsigned char data[send_node_block_size];

    typedef SeqNode InnerNode;

    SendDataInfo(NodePool<SeqNode> * p)
     : first_sequence(0), using_size(0),
       blank_size(send_node_block_size),
       seq_list(p), prev(NULL), next(NULL)
    {


    }

    ~SendDataInfo()
    {
        clear();
    }

    int get_relation(seq_type front_sequence, uint16_t offset)
    {
        assert(0 != offset);
        assert(front_sequence + offset > front_sequence);

        if (first_sequence > front_sequence)
        {
            return(1);
        }
        else if (first_sequence + using_size <= front_sequence)
        {
            return(-1);
        }
        else
        {
            assert(front_sequence + offset <= first_sequence + using_size);
            return(0);
        }
    }

    SeqNode * find_seq_node(const SeqNode * node)
    {
        assert(NULL != node);

        SeqNode * ret = seq_list.head;
        while (NULL != ret)
        {
            int comp = node->compare(ret);
            if (comp < 0)
            {
                return(NULL);
            }
            else if (comp > 0)
            {
                ret = ret->next;
            }
            else
            {
                return(ret);
            }
        }
        return(NULL);
    }

    void clear()
    {
        seq_list.clear();
    }
} SendDataNode;

typedef struct RttInfo
{
    enum { g = 8, h = 4 };
    enum { min_rto = 200, max_rto = 1000 };
    time_type srtt;
    time_type rttvar;
    time_type rto;

    RttInfo() : srtt(0), rttvar(250), rto(srtt + 4 * rttvar)
    {

    }

    void update(time_type rtt)
    {
        int delta = rtt - srtt;
        srtt += delta / g;

        if (delta < 0)
        {
            delta = -delta;
        }

        rttvar += (delta - rttvar) / h;

        rto = srtt + 4 * rttvar;

        if (rto < min_rto)
        {
            rto = min_rto;
        }
        else if (rto > max_rto)
        {
            rto = max_rto;
        }
    }
} RttType;

typedef struct AckInfo
{
    seq_type front_sequence;
    uint16_t region_size;
    uint8_t count;

    AckInfo() : front_sequence(0), region_size(0), count(4)
    {

    }

    AckInfo & operator = (const struct AckInfo & other)
    {
        if (this != &other)
        {
            front_sequence = other.front_sequence;
            region_size = other.region_size;
            count = other.count;
        }
        return(*this);
    }
} AckRegion;

typedef struct RegionInfo
{
    seq_type front_sequence;
    seq_type behind_sequence;
    struct RegionInfo * prev;
    struct RegionInfo * next;

    typedef void InnerNode;

    RegionInfo(NodePool<void> * p)
     : front_sequence(0), behind_sequence(0), prev(NULL), next(NULL)
    {

    }

    ~RegionInfo()
    {
        clear();
    }

    void clear()
    {

    }
} RegionNode;

typedef struct RecvDataInfo
{
    enum { recv_node_block_size = 16384 };
    seq_type min_sequence;
    seq_type max_sequence;
    struct RecvDataInfo * prev;
    struct RecvDataInfo * next;
    unsigned char data[recv_node_block_size];

    typedef void InnerNode;

    RecvDataInfo(NodePool<void> * p)
     : min_sequence(0), max_sequence(0), prev(NULL), next(NULL)
    {

    }

    ~RecvDataInfo()
    {
        clear();
    }

    void clear()
    {

    }
} RecvDataNode;


#endif

rudp.h:

#ifndef __RUDP_H__
#define __RUDP_H__


#include "nodes.hpp"
#include "lock.h"

class RudpMgr;

class Rudp
{
public:  /* both end */
    Rudp(RudpMgr * mgr, int sockfd, uint32_t unique_id);
    ~Rudp();

public:  /* send end, for user */
    bool send_data(unsigned char * data, uint16_t len, bool reliable);
    bool send_heart_beat_package();

public:  /* both end, for RudpMgr */
    bool recv_data(unsigned char * data, uint16_t len);
    bool is_alive();
    uint32_t get_unique_id();
    void kill();

private: /* both end */
    enum { unreliable_udp, reliable_udp, ack_message, heart_beat };
    RudpMgr * m_rudp_mgr;
    int m_sockfd;
    uint32_t m_unique_id;
    bool m_is_alive;
    time_type m_last_recv_heart_beat_time;

public:  /* send end, for RudpMgr */
    bool has_data_to_send();
    bool send_data();

private: /* send end */
    bool store_send_data(unsigned char * data, uint16_t len);
    bool recv_ack(unsigned char * data, uint16_t len);

    void send_new_data(uint8_t & send_count);
    void send_old_data(uint8_t & send_count);
    bool send_rudp_package(seq_type front_index, uint8_t send_index, unsigned char * data, uint16_t len);

    void lock_sender();
    void unlock_sender();

private: /* send end */
    MutexLocker m_send_mutex_locker;

    RttType m_rtt;

    seq_type m_next_data_node_first_sequence;

    uint8_t m_max_send_count;

    uint16_t m_pending_count;
    uint16_t m_max_pending_count;

    SendDataNode * m_last_send_old_data_node;
    SeqNode  * m_next_send_old_seq_node;

    SendDataNode * m_next_send_new_data_node;
    uint16_t m_data_offset;

    NodePool<TimeNode> m_send_time_pool;
    NodePool<SeqNode>  m_send_seq_pool;
    NodePool<SendDataNode> m_send_data_pool;
    NodeLink<SendDataNode> m_send_data_list;

public:  /* recv end, for RudpMgr */
    bool analytic_data();

private: /* recv end */
    bool store_recv_data(unsigned char * data, uint16_t len);
    bool send_ack(uint8_t send_index);
    bool do_analytic_data();

    void update_ack_nodes(seq_type front_sequence, uint16_t region_size);
    int update_recv_region(seq_type front_sequence, uint16_t region_size);

    void lock_recver();
    void unlock_recver();

private: /* recv end */
    MutexLocker m_recv_mutex_locker;

    AckRegion m_ack_node[4];
    int m_ack_node_count;
    int m_new_ack_node_position;

    AckRegion  m_ack_region;

    seq_type m_min_need_sequence;
    seq_type m_max_read_sequence;

    bool m_turn_to_analytic_len;
    uint16_t m_need_analytic_data_len;

    NodePool<RegionNode> m_region_pool;
    NodeLink<RegionNode> m_region_list;

    NodePool<RecvDataNode> m_recv_data_pool;
    NodeLink<RecvDataNode> m_recv_data_list;
};


#endif

rudp.cpp:

#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include "common.h"
#include "rudp.h"
#include "rudpmgr.h"

#include <cstdio>

Rudp::Rudp(RudpMgr * mgr, int sockfd, uint32_t unique_id)
 : m_rudp_mgr(mgr),
   m_sockfd(sockfd),
   m_unique_id(unique_id),
   m_is_alive(true), 
   m_send_time_pool(NULL),
   m_send_seq_pool(&m_send_time_pool),
   m_send_data_pool(&m_send_seq_pool),
   m_send_data_list(&m_send_data_pool),
   m_region_pool(NULL),
   m_region_list(&m_region_pool),
   m_recv_data_pool(NULL),
   m_recv_data_list(&m_recv_data_pool)
{
    if (NULL == m_rudp_mgr || m_sockfd < 0)
    {
        assert(false);
        exit(1);
    }

    m_last_recv_heart_beat_time = getcurtime();

    /* send end */
    m_next_data_node_first_sequence = 0;
    m_max_send_count = 20;
    m_pending_count = 0;
    m_max_pending_count = 100;
    m_last_send_old_data_node = NULL;
    m_next_send_old_seq_node = NULL;
    m_next_send_new_data_node = NULL;
    m_data_offset = 0;

    /* recv end */
    m_ack_node_count = 0;
    m_new_ack_node_position = -1;
    m_min_need_sequence = 0;
    m_max_read_sequence = 0;
    m_turn_to_analytic_len = true;
    m_need_analytic_data_len = sizeof(uint16_t);
}

Rudp::~Rudp()
{

}

uint32_t Rudp::get_unique_id()
{
    return(m_unique_id);
}

void Rudp::kill()
{
    m_is_alive = false;
}

void Rudp::lock_sender()
{
    m_send_mutex_locker.lock();
}

void Rudp::unlock_sender()
{
    m_send_mutex_locker.unlock();
}

void Rudp::lock_recver()
{
    m_recv_mutex_locker.lock();
}

void Rudp::unlock_recver()
{
    m_recv_mutex_locker.unlock();
}

bool Rudp::send_data(unsigned char * data, uint16_t len, bool reliable)
{
    if (reliable)
    {
        lock_sender();
        bool ret = store_send_data(data, len);
        unlock_sender();
        return(ret);
    }
    else
    {
        if (len > 4096 - 1)
        {
            return(false);
        }

        char buff[4096];
        buff[0] = (unsigned char)unreliable_udp;
        memcpy(buff + 1, data, len);
        len += 1;

        return(-1 != write(m_sockfd, buff, len));
    }
}

bool Rudp::send_heart_beat_package()
{
    char buff[1] = { heart_beat };
    return(-1 != write(m_sockfd, buff, 1));
}

bool Rudp::recv_data(unsigned char * data, uint16_t len)
{
    if (len < 1)
    {
        assert(false);
        return(false);
    }

    unsigned char data_type = data[0];
    data += 1;
    len -= 1;

    bool ret = false;
    if (unreliable_udp == data_type)
    {
        ret = m_rudp_mgr->handle_data(m_unique_id, data, len);
    }
    else if (reliable_udp == data_type)
    {
        lock_recver();
        ret = store_recv_data(data, len); /* recv end */
        unlock_recver();
    }
    else if (ack_message == data_type)
    {
        lock_sender();
        ret = recv_ack(data, len); /* send end */
        unlock_sender();
    }
    else if (heart_beat == data_type)
    {
        m_last_recv_heart_beat_time = getcurtime();
        ret = true;
    }
    else /* unknown data type */
    {
        assert(false);
        ret = false;
    }
    return(ret);
}

bool Rudp::is_alive()
{
    return(m_is_alive && getcurtime() - m_last_recv_heart_beat_time < 2 * 60 * 1000);
}

bool Rudp::store_send_data(unsigned char * data, uint16_t len)
{
    uint16_t nlen = len;
    big2little(&nlen, sizeof(uint16_t));
    unsigned char * len_data = (unsigned char *)&nlen;
    uint16_t len_data_len = sizeof(uint16_t);

    assert(0 == len || NULL != data);

    SendDataNode * tail = m_send_data_list.tail;
    uint16_t tail_using_size = 0;
    uint16_t tail_blank_size = 0;

    if (NULL != tail && tail->blank_size > 0)
    {
        tail_using_size = tail->using_size;
        tail_blank_size = tail->blank_size;

        uint16_t write_len = min(len_data_len, tail->blank_size);
        memcpy(tail->data + tail->using_size, len_data, write_len);
        tail->using_size += write_len;
        tail->blank_size -= write_len;
        len_data += write_len;
        len_data_len -= write_len;

        if (tail->blank_size > 0 && len > 0)
        {
            write_len = min(len, tail->blank_size);
            memcpy(tail->data + tail->using_size, data, write_len);
            data += write_len;
            len -= write_len;
            tail->using_size += write_len;
            tail->blank_size -= write_len;
        }

        if (0 == len_data_len && 0 == len)
        {
            return(true);
        }
    }

    seq_type next_data_node_first_sequence = m_next_data_node_first_sequence;
    NodeLink<SendDataNode> node_list(&m_send_data_pool);

    while (true)
    {
        SendDataNode * node = m_send_data_pool.get_node();
        if (NULL == node)
        {
            if (0 != tail_using_size)
            {
                tail->using_size = tail_using_size;
                tail->blank_size = tail_blank_size;
            }
            m_next_data_node_first_sequence = next_data_node_first_sequence;
            return(false);
        }

        node->first_sequence = m_next_data_node_first_sequence;
        m_next_data_node_first_sequence += node->blank_size;

        if (len_data_len > 0)
        {
            assert(len_data_len < node->blank_size);
            memcpy(node->data, len_data, len_data_len);
            node->using_size += len_data_len;
            node->blank_size -= len_data_len;
            len_data_len = 0;
        }

        if (len > 0)
        {
            assert(node->blank_size > 0);
            uint16_t write_len = min(len, node->blank_size);
            memcpy(node->data + node->using_size, data, write_len);
            node->using_size += write_len;
            node->blank_size -= write_len;
            data += write_len;
            len -= write_len;
        }

        node_list.push_back(node);

        if (0 == len_data_len && 0 == len)
        {
            break;
        }
    }

    m_send_data_list.push_back(node_list);

    return(true);
}

bool Rudp::has_data_to_send()
{
    SendDataNode * sd_node = NULL;

    sd_node = m_send_data_list.head;
    if (NULL == sd_node)
    {
        return(false);
    }
    if (sd_node->seq_list.size > 0)
    {
        return(true);
    }

    sd_node = m_next_send_new_data_node;
    if (NULL == sd_node)
    {
        assert(0 == m_data_offset);
        sd_node = m_send_data_list.head;
        assert(NULL != sd_node);
        assert(m_data_offset <= sd_node->using_size);
        assert(NULL == sd_node->seq_list.head);
    }

    return(m_data_offset < sd_node->using_size);
}

bool Rudp::send_data()
{
    lock_sender();
    uint8_t send_count = 0;
    send_old_data(send_count); /* send old data */
    send_new_data(send_count); /* send new data */
    unlock_sender();
    return(true);
}

void Rudp::send_new_data(uint8_t & send_count)
{
    if (send_count >= m_max_send_count || m_pending_count >= m_max_pending_count)
    {
        return;
    }

    if (NULL == m_next_send_new_data_node)
    {
        assert(0 == m_data_offset);

        m_next_send_new_data_node = m_send_data_list.head;
        if (NULL == m_next_send_new_data_node)
        {
            return;
        }
        else
        {
            assert(NULL == m_next_send_new_data_node->seq_list.head);
        }
    }

    while (true)
    {
        assert(m_data_offset <= m_next_send_new_data_node->using_size);

        seq_type max_sequence = m_next_send_new_data_node->first_sequence + m_next_send_new_data_node->using_size;

        while (m_data_offset < m_next_send_new_data_node->using_size)
        {
            SeqNode * s_node = m_send_seq_pool.get_node();
            TimeNode * t_node = m_send_time_pool.get_node();
            if (NULL == s_node || NULL == t_node)
            {
                m_send_seq_pool.put_node(s_node);
                m_send_time_pool.put_node(t_node);
                return;
            }

            t_node->index = 1;
            s_node->front_sequence = m_next_send_new_data_node->first_sequence + m_data_offset;
            s_node->behind_sequence = min(max_sequence, s_node->front_sequence + 512);

            assert(s_node->front_sequence < s_node->behind_sequence);

            uint16_t region_size = (uint16_t)(s_node->behind_sequence - s_node->front_sequence);

            send_rudp_package(s_node->front_sequence, t_node->index, m_next_send_new_data_node->data + m_data_offset, region_size);

            t_node->time = getcurtime();
            s_node->time_list.push_back(t_node);
            m_next_send_new_data_node->seq_list.push_back(s_node);

            ++send_count;
            ++m_pending_count;
            m_data_offset += region_size;

            if (send_count >= m_max_send_count || m_pending_count >= m_max_pending_count)
            {
                return;
            }
        }

        assert(m_data_offset == m_next_send_new_data_node->using_size);

        if (0 == m_next_send_new_data_node->blank_size &&
            NULL != m_next_send_new_data_node->next)
        {
            m_next_send_new_data_node = m_next_send_new_data_node->next;
            m_data_offset = 0;
        }
        else
        {
            break;
        }
    }

    assert(m_pending_count <= m_max_pending_count);
}

void Rudp::send_old_data(uint8_t & send_count)
{
    if (send_count >= m_max_send_count)
    {
        return;
    }

    SendDataNode * last_data_node = m_last_send_old_data_node;
    SeqNode * next_seq_node = m_next_send_old_seq_node;

    if (NULL == last_data_node)
    {
        assert(NULL == next_seq_node);

        last_data_node = m_send_data_list.head;
        if (NULL == last_data_node)
        {
            return;
        }

        next_seq_node = last_data_node->seq_list.head;
        if (NULL == next_seq_node)
        {
            return;
        }
    }

    while (NULL != next_seq_node && send_count < m_max_send_count)
    {
        NodeLink<TimeNode> & time_list = next_seq_node->time_list;

        assert(NULL != time_list.tail);

        if (getcurtime() - time_list.tail->time > m_rtt.rto)
        {
            TimeNode * node = m_send_time_pool.get_node();
            if (NULL == node)
            {
                return;
            }
            node->index = time_list.tail->index + 1;
            if (0 == node->index)
            {
                time_list.clear();
                node->index = 1;
            }

            assert(next_seq_node->front_sequence >= last_data_node->first_sequence);
            assert(next_seq_node->front_sequence < next_seq_node->behind_sequence);
            assert(next_seq_node->behind_sequence <= last_data_node->first_sequence + last_data_node->using_size);

            uint16_t offset = next_seq_node->front_sequence - last_data_node->first_sequence;
            uint16_t region_size = next_seq_node->behind_sequence - next_seq_node->front_sequence;

            send_rudp_package(next_seq_node->front_sequence, node->index, last_data_node->data + offset, region_size);

            node->time = getcurtime();
            time_list.push_back(node);

            ++send_count;
        }

        next_seq_node = next_seq_node->next;
        if (NULL == next_seq_node)
        {
            last_data_node = last_data_node->next;
            if (NULL == last_data_node)
            {
                m_last_send_old_data_node = NULL;
                m_next_send_old_seq_node = NULL;
                break;
            }
            else
            {
                next_seq_node = last_data_node->seq_list.head;
            }
        }
    }

    m_next_send_old_seq_node = next_seq_node;
    if (NULL == m_next_send_old_seq_node)
    {
        m_last_send_old_data_node = NULL;
    }
    else
    {
        m_last_send_old_data_node = last_data_node;
    }
}

bool Rudp::send_rudp_package(seq_type front_sequence, uint8_t send_index, unsigned char * data, uint16_t len)
{
    unsigned char buff[1024];

    seq_type net_front_sequence = front_sequence;
    uint8_t net_index = send_index;

    big2little(&net_front_sequence, sizeof(seq_type));
    big2little(&net_index, sizeof(uint8_t));

    assert(len + 1 + sizeof(seq_type) + sizeof(uint8_t) <= 1024);

    uint16_t send_len = 0;
    buff[0] = (unsigned char)reliable_udp;
    send_len += 1;
    memcpy(buff + send_len, &net_front_sequence, sizeof(seq_type));
    send_len += sizeof(seq_type);
    memcpy(buff + send_len, &net_index, sizeof(uint8_t));
    send_len += sizeof(uint8_t);
    memcpy(buff + send_len, data, len);
    send_len += len;

    assert(send_len <= 576 - 20 - 8);

    return(-1 != write(m_sockfd, buff, send_len));
}

bool Rudp::recv_ack(unsigned char * data, uint16_t len)
{
    assert(m_pending_count <= m_max_pending_count);

    if (0 != (len - sizeof(uint8_t) - sizeof(seq_type)) %
             (sizeof(seq_type) + sizeof(uint16_t)))
    {
        assert(false);
        return(false);
    }

    if (len - sizeof(uint8_t) - sizeof(seq_type) <
        sizeof(seq_type) + sizeof(uint16_t))
    {
        assert(false);
        return(false);
    }

    time_type ack_time = getcurtime();

    uint8_t send_index = 0;

    memcpy(&send_index, data, sizeof(uint8_t));
    data += sizeof(uint8_t);
    len -= sizeof(uint8_t);

    big2little(&send_index, sizeof(uint8_t));

    if (0 == send_index)
    {
        assert(false);
        return(false);
    }

    SendDataNode * sd_node = m_send_data_list.head;
    if (NULL == sd_node)
    {
        return(true);
    }

    bool first_loop = true;

    while (NULL != sd_node)
    {
        seq_type front_sequence = 0;
        uint16_t region_size = 0;

        memcpy(&front_sequence, data, sizeof(seq_type));
        data += sizeof(seq_type);
        len -= sizeof(seq_type);
        memcpy(®ion_size, data, sizeof(uint16_t));
        data += sizeof(uint16_t);
        len -= sizeof(uint16_t);

        big2little(&front_sequence, sizeof(seq_type));
        big2little(®ion_size, sizeof(uint16_t));

        if (front_sequence + region_size <= front_sequence)
        {
            assert(false);
            return(false);
        }

        int relation = 0;

        while (NULL != sd_node)
        {
            relation = sd_node->get_relation(front_sequence, region_size);
            if (relation < 0)
            {
                sd_node = sd_node->next;
            }
            else
            {
                break;
            }
        }

        if (0 == relation)
        {
            SeqNode node(&m_send_time_pool);
            node.front_sequence = front_sequence;
            node.behind_sequence = front_sequence + region_size;

            SeqNode * s_node = sd_node->find_seq_node(&node);
            if (NULL != s_node)
            {
                TimeNode * t_node = s_node->find_time_node(send_index);
                if (NULL != t_node)
                {
                    if (first_loop)
                    {
                        m_rtt.update(ack_time - t_node->time);
                    }

                    if (s_node == m_next_send_old_seq_node)
                    {
                        m_next_send_old_seq_node = m_next_send_old_seq_node->next;
                        if (NULL == m_next_send_old_seq_node)
                        {
                            m_last_send_old_data_node = m_last_send_old_data_node->next;
                            if (NULL != m_last_send_old_data_node)
                            {
                                m_next_send_old_seq_node = m_last_send_old_data_node->seq_list.head;
                                if (NULL == m_next_send_old_seq_node)
                                {
                                    m_last_send_old_data_node = NULL;
                                }
                            }
                        }
                    }

                    sd_node->seq_list.erase(s_node);
                    --m_pending_count;
                }
            }
        }

        if (len < sizeof(seq_type) + sizeof(uint16_t))
        {
            break;
        }

        if (first_loop)
        {
            sd_node = m_send_data_list.head;
            first_loop = false;
        }
    }

    if (sizeof(seq_type) != len)
    {
        assert(false);
        return(false);
    }

    seq_type min_recved_sequence = 0;
    memcpy(&min_recved_sequence, data, sizeof(seq_type));
    big2little(&min_recved_sequence, sizeof(seq_type));

    sd_node = m_send_data_list.head;
    while (NULL != sd_node && 0 == sd_node->blank_size &&
           sd_node->first_sequence + sd_node->using_size <= min_recved_sequence)
    {
        if (sd_node == m_last_send_old_data_node)
        {
            m_last_send_old_data_node = m_last_send_old_data_node->next;
            if (NULL == m_last_send_old_data_node)
            {
                m_next_send_old_seq_node = NULL;
            }
            else
            {
                m_next_send_old_seq_node = m_last_send_old_data_node->seq_list.head;
                if (NULL == m_next_send_old_seq_node)
                {
                    m_last_send_old_data_node = NULL;
                }
            }
        }

        if (sd_node == m_next_send_new_data_node)
        {
            assert(m_data_offset == m_next_send_new_data_node->using_size);
            m_next_send_new_data_node = m_next_send_new_data_node->next;
            m_data_offset = 0;
        }

        m_pending_count -= sd_node->seq_list.size;

        m_send_data_list.erase(sd_node);
        sd_node = m_send_data_list.head;
    }

    if (NULL == sd_node || sd_node->first_sequence >= min_recved_sequence)
    {
        return(true);
    }

    SeqNode * s_node = sd_node->seq_list.head;
    while (NULL != s_node && s_node->behind_sequence <= min_recved_sequence)
    {
        if (s_node == m_next_send_old_seq_node)
        {
            m_next_send_old_seq_node = m_next_send_old_seq_node->next;
            if (NULL == m_next_send_old_seq_node)
            {
                m_last_send_old_data_node = m_last_send_old_data_node->next;
                if (NULL != m_last_send_old_data_node)
                {
                    m_next_send_old_seq_node = m_last_send_old_data_node->seq_list.head;
                    if (NULL == m_next_send_old_seq_node)
                    {
                        m_last_send_old_data_node = NULL;
                    }
                }
            }
        }

        sd_node->seq_list.erase(s_node);
        s_node = sd_node->seq_list.head;

        --m_pending_count;
    }

    assert(m_pending_count <= m_max_pending_count);

    return(true);
}

bool Rudp::store_recv_data(unsigned char * data, uint16_t len)
{
    assert(len > sizeof(seq_type) + sizeof(uint8_t));

    RecvDataNode * node = m_recv_data_pool.get_node();
    if (NULL == node)
    {
        return(false);
    }
    seq_type front_sequence = 0;
    uint8_t send_index = 0;

    memcpy(&front_sequence, data, sizeof(seq_type));
    data += sizeof(seq_type);
    len -= sizeof(seq_type);
    memcpy(&send_index, data, sizeof(uint8_t));
    data += sizeof(uint8_t);
    len -= sizeof(uint8_t);

    big2little(&front_sequence, sizeof(seq_type));
    big2little(&send_index, sizeof(uint8_t));

    assert(len > 0);

    seq_type min_sequence = front_sequence / node->recv_node_block_size * node->recv_node_block_size;
    seq_type max_sequence = min_sequence + node->recv_node_block_size;

    assert(min_sequence < max_sequence);

    if (front_sequence + len <= min_sequence ||
        front_sequence + len > max_sequence)
    {
        assert(false);
        m_recv_data_pool.put_node(node);
        return(false);
    }

    int ret = update_recv_region(front_sequence, len);
    if (-1 == ret)
    {
        m_recv_data_pool.put_node(node);
        return(false);
    }

    update_ack_nodes(front_sequence, len);

    if (0 == ret)
    {
        m_recv_data_pool.put_node(node);
        send_ack(send_index);
        return(true);
    }

    RecvDataNode * p_node = NULL;
    RecvDataNode * rd_node = m_recv_data_list.head;
    while (NULL != rd_node && min_sequence >= rd_node->max_sequence)
    {
        p_node = rd_node;
        rd_node = rd_node->next;
    }

    if (NULL == rd_node)
    {
        rd_node = node;
        m_recv_data_list.push_back(node);
        rd_node->min_sequence = min_sequence;
        rd_node->max_sequence = max_sequence;
    }
    else
    {
        if (max_sequence <= rd_node->min_sequence)
        {
            rd_node = node;
            if (NULL == p_node)
            {
                m_recv_data_list.push_front(node);
            }
            else
            {
                m_recv_data_list.push_after(p_node, node);
            }
            rd_node->min_sequence = min_sequence;
            rd_node->max_sequence = max_sequence;
        }
        else
        {
            assert(min_sequence == rd_node->min_sequence &&
                   max_sequence == rd_node->max_sequence);
            m_recv_data_pool.put_node(node);
        }
    }

    uint16_t offset = front_sequence - rd_node->min_sequence;
    memcpy(rd_node->data + offset, data, len);

    send_ack(send_index);

    return(true);
}

void Rudp::update_ack_nodes(seq_type front_sequence, uint16_t region_size)
{
    assert(front_sequence + region_size > front_sequence);

    int del_count = 0;

    for (int index = 0; index < m_ack_node_count; ++index)
    {
        AckRegion & check_region = m_ack_node[index];
        if (4 == check_region.count)
        {
            ++del_count;
            continue;
        }

        if (m_min_need_sequence >= check_region.front_sequence + check_region.region_size)
        {
            check_region.count = 4;
            ++del_count;
            continue;
        }

        if (del_count > 0)
        {
            AckRegion & modify_region = m_ack_node[index - del_count];
            modify_region = check_region;
            check_region.count = 4;
        }
    }

    m_ack_node_count -= del_count;

    assert(m_ack_node_count >= 0 && m_ack_node_count < 4);

    bool need_move = true;
    m_new_ack_node_position = 0;
    while (m_new_ack_node_position < m_ack_node_count)
    {
        AckRegion & check_region = m_ack_node[m_new_ack_node_position];

        if (check_region.front_sequence < front_sequence)
        {
            ++m_new_ack_node_position;
            ++check_region.count;
            continue;
        }

        if (check_region.front_sequence == front_sequence)
        {
            check_region.count = 1;
            need_move = false;
        }

        break;
    }

    for (int index = m_ack_node_count - 1; index >= m_new_ack_node_position; --index)
    {
        AckRegion & move_region = m_ack_node[index];
        ++move_region.count;
        if (need_move)
        {
            m_ack_node[index + 1] = move_region;
        }
    }

    if (need_move)
    {
        AckRegion & modify_region = m_ack_node[m_new_ack_node_position];
        modify_region.front_sequence = front_sequence;
        modify_region.region_size = region_size;
        modify_region.count = 1;
        ++m_ack_node_count;
    }
}

int Rudp::update_recv_region(seq_type front_sequence, uint16_t region_size)
{
    seq_type behind_sequence = front_sequence + region_size;
    if (front_sequence >= behind_sequence)
    {
        assert(false);
        return(-1);
    }

    if (behind_sequence <= m_min_need_sequence)
    {
        return(0);
    }

    RegionNode * p_node = NULL;
    RegionNode * r_node = m_region_list.head;
    while (NULL != r_node && front_sequence > r_node->behind_sequence)
    {
        p_node = r_node;
        r_node = r_node->next;
    }

    if (NULL == r_node || behind_sequence < r_node->front_sequence)
    {
        if (front_sequence <= m_min_need_sequence)
        {
            m_min_need_sequence = behind_sequence;
            return(1);
        }

        RegionNode * node = m_region_pool.get_node();
        if (NULL == node)
        {
            return(-1);
        }
        node->front_sequence = front_sequence;
        node->behind_sequence = behind_sequence;

        if (NULL == r_node)
        {
            m_region_list.push_back(node);
        }
        else
        {
            if (NULL == p_node)
            {
                m_region_list.push_front(node);
            }
            else
            {
                m_region_list.push_after(p_node, node);
            }
        }

        return(1);
    }

    if (r_node->front_sequence > front_sequence)
    {
        r_node->front_sequence = front_sequence;
    }
    if (r_node->behind_sequence < behind_sequence)
    {
        r_node->behind_sequence = behind_sequence;
    }

    RegionNode * n_node = r_node->next;
    while (NULL != n_node && r_node->behind_sequence >= n_node->front_sequence)
    {
        if (r_node->behind_sequence < n_node->behind_sequence)
        {
            r_node->behind_sequence = n_node->behind_sequence;
        }
        m_region_list.erase(n_node);
        n_node = r_node->next;
    }

    RegionNode * h_node = m_region_list.head;
    if (m_min_need_sequence >= h_node->front_sequence)
    {
        assert(h_node == r_node);
        assert(m_min_need_sequence < h_node->behind_sequence);
        m_min_need_sequence = h_node->behind_sequence;
        m_region_list.erase(h_node);
    }

    return(1);
}

bool Rudp::send_ack(uint8_t send_index)
{
    unsigned char buff[1024];

    big2little(&send_index, sizeof(uint8_t));

    uint16_t send_len = 0;
    buff[0] = (unsigned char)ack_message;
    send_len += 1;
    memcpy(buff + send_len, &send_index, sizeof(uint8_t));
    send_len += sizeof(uint8_t);

    assert(m_new_ack_node_position >= 0 && m_new_ack_node_position < m_ack_node_count);

    AckRegion * a_node = &m_ack_node[m_new_ack_node_position];
    seq_type front_sequence = a_node->front_sequence;
    uint16_t region_size = a_node->region_size;

    big2little(&front_sequence, sizeof(seq_type));
    big2little(®ion_size, sizeof(uint16_t));

    memcpy(buff + send_len, &front_sequence, sizeof(seq_type));
    send_len += sizeof(seq_type);
    memcpy(buff + send_len, ®ion_size, sizeof(uint16_t));
    send_len += sizeof(uint16_t);

    for (int index = 0; index < m_ack_node_count; ++index)
    {
        if (index != m_new_ack_node_position)
        {
            a_node = &m_ack_node[index];
            front_sequence = a_node->front_sequence;
            region_size = a_node->region_size;

            big2little(&front_sequence, sizeof(seq_type));
            big2little(®ion_size, sizeof(uint16_t));

            memcpy(buff + send_len, &front_sequence, sizeof(seq_type));
            send_len += sizeof(seq_type);
            memcpy(buff + send_len, ®ion_size, sizeof(uint16_t));
            send_len += sizeof(uint16_t);
        }
    }

    seq_type min_need_sequence = m_min_need_sequence;

    big2little(&min_need_sequence, sizeof(seq_type));

    memcpy(buff + send_len, &min_need_sequence, sizeof(seq_type));
    send_len += sizeof(seq_type);

    assert(send_len <= 576 - 20 - 8);

    return(-1 != write(m_sockfd, buff, send_len));
}

bool Rudp::analytic_data()
{
    lock_recver();
    bool ret = do_analytic_data();
    unlock_recver();
    return(ret);
}

bool Rudp::do_analytic_data()
{
    if (m_min_need_sequence - m_max_read_sequence < m_need_analytic_data_len)
    {
        return(true);
    }

    unsigned char buff[65535];
    uint16_t offset = 0;
    uint16_t len = 0;
    RecvDataNode * rd_node = NULL;

    while (m_min_need_sequence - m_max_read_sequence >= m_need_analytic_data_len)
    {
        if (0 == len)
        {
            rd_node = m_recv_data_list.head;
            if (NULL == rd_node ||
                m_max_read_sequence < rd_node->min_sequence ||
                m_max_read_sequence >= rd_node->max_sequence)
            {
                assert(false);
                exit(1);
                return(false);
            }

            offset = m_max_read_sequence - rd_node->min_sequence;
            len = min(rd_node->max_sequence, m_min_need_sequence) - m_max_read_sequence;
        }

        if (len < m_need_analytic_data_len)
        {
            memcpy(buff, rd_node->data + offset, len);
            m_max_read_sequence += len;
            uint16_t left_len = m_need_analytic_data_len - len;
            while (left_len > 0)
            {
                m_recv_data_list.erase(rd_node);
                rd_node = m_recv_data_list.head;
                if (NULL == rd_node ||
                    m_max_read_sequence != rd_node->min_sequence)
                {
                    assert(false);
                    exit(1);
                    return(false);
                }

                len = min(rd_node->max_sequence, m_min_need_sequence) - m_max_read_sequence;

                uint16_t write_len = min(len, left_len);

                memcpy(buff + m_need_analytic_data_len - left_len, rd_node->data, write_len);
                offset = write_len;
                len -= write_len;
                m_max_read_sequence += write_len;
                left_len -= write_len;
            }
        }
        else
        {
            memcpy(buff, rd_node->data + offset, m_need_analytic_data_len);
            offset += m_need_analytic_data_len;
            len -= m_need_analytic_data_len;
            m_max_read_sequence += m_need_analytic_data_len;
        }

        if (m_turn_to_analytic_len)
        {
            assert(sizeof(uint16_t) == m_need_analytic_data_len);
            uint16_t data_len = 0;
            memcpy(&data_len, buff, m_need_analytic_data_len);
            big2little(&data_len, m_need_analytic_data_len);
            m_need_analytic_data_len = data_len;
        }
        else
        {
            m_rudp_mgr->handle_data(m_unique_id, buff, m_need_analytic_data_len);
            m_need_analytic_data_len = sizeof(uint16_t);
        }

        m_turn_to_analytic_len = !m_turn_to_analytic_len;

        if (m_max_read_sequence == rd_node->max_sequence)
        {
            assert(0 == len);
            m_recv_data_list.erase(rd_node);
        }
    }

    return(true);
}

rudpmgr.h:

#ifndef __RUDP_MANAGER_H__
#define __RUDP_MANAGER_H__


#include <map>
#include <vector>
#include <string>
using std::map;
using std::vector;
using std::string;

#include <cassert>
#include <cstdlib>
#include <pthread.h>
#include <sys/select.h>
#include "types.h"
#include "lock.h"

class Rudp;

class RudpMgrSink;

class RudpMgr
{
public:
    RudpMgr(uint16_t port = 0);
    ~RudpMgr();

    void set_sink(RudpMgrSink * sink);
    void run();

    bool send_data(uint32_t conn, unsigned char * data, uint16_t len, bool reliable);
    bool handle_data(uint32_t conn, unsigned char * data, uint16_t len);

    void create_rudp(const char * host, uint16_t port);
    void destroy_rudp(uint32_t unique_id);

    int recv_data_thread();
    int send_data_thread();
    int handle_data_thread();

private:
    void destroy_rudp(uint32_t unique_id, bool is_locked);

private:
    struct sock_rudp
    {
        int connfd;
        Rudp * prudp;
    };

    RudpMgrSink * m_rudp_mgr_sink;

    int m_listenfd;
    int m_maxrfdp1;
    fd_set m_rset;

    bool m_is_running;
    pthread_t m_recv_thread;
    pthread_t m_send_thread;
    pthread_t m_handle_thread;

    MutexLocker m_mutex_locker;
    RWLocker m_rw_locker;
    uint32_t m_unique_id_creator;
    vector<uint32_t> m_unique_id_vector;
    map<string, int> m_address_socket_map;
    vector<sock_rudp> m_sock_rudp_vector;
};


#endif

rudpmgr.cpp:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include "common.h"
#include "rudp.h"
#include "rudpmgrsink.h"
#include "rudpmgr.h"


static void * recv_data_func(void * arg)
{
    RudpMgr * mgr = (RudpMgr *)arg;
    int ret = mgr->recv_data_thread();
    return((void *)ret);
}

static void * send_data_func(void * arg)
{
    RudpMgr * mgr = (RudpMgr *)arg;
    int ret = mgr->send_data_thread();
    return((void *)ret);
}

static void * handle_data_func(void * arg)
{
    RudpMgr * mgr = (RudpMgr *)arg;
    int ret = mgr->handle_data_thread();
    return((void *)ret);
}

static bool readable_timeout(int sockfd, int sec)
{
    fd_set rset;
    struct timeval tv;

    FD_ZERO(&rset);
    FD_SET(sockfd, &rset);

    tv.tv_sec = sec;
    tv.tv_usec = 0;

    return(select(sockfd + 1, &rset, NULL, NULL, &tv) > 0);
}

RudpMgr::RudpMgr(uint16_t port)
 : m_rudp_mgr_sink(NULL), m_listenfd(-1), m_maxrfdp1(-1), m_is_running(false), m_unique_id_creator(0)
{
    m_unique_id_creator = (uint32_t)rand();

    FD_ZERO(&m_rset);

    /* client */
    if (0 == port)
    {
        return;
    }

    /* server */
    if (-1 == (m_listenfd = socket(AF_INET, SOCK_DGRAM, 0)))
    {
        perror("socket error");
        exit(1);
    }

    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(port);

    if (-1 == bind(m_listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))
    {
        perror("bind error");
        exit(1);
    }

    FD_SET(m_listenfd, &m_rset);
    m_maxrfdp1 = m_listenfd + 1;
}

RudpMgr::~RudpMgr()
{
    if (m_is_running)
    {
        int error_no = 0;
        if (0 != (error_no = pthread_cancel(m_recv_thread)))
        {
            printf("pthread_cancel recv_thread error: %s\n", strerror(error_no));
        }
        if (0 != (error_no = pthread_cancel(m_send_thread)))
        {
            printf("pthread_cancel send_thread error: %s\n", strerror(error_no));
        }
        if (0 != (error_no = pthread_cancel(m_handle_thread)))
        {
            printf("pthread_cancel handle_thread error: %s\n", strerror(error_no));
        }
        sleep(1);
    }

    if (-1 != m_listenfd)
    {
        close(m_listenfd);
    }

    m_rw_locker.wrlock();
    vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
    while (m_sock_rudp_vector.end() != vsr_iter)
    {
        close(vsr_iter->connfd);
        delete vsr_iter->prudp;
        ++vsr_iter;
    }
    m_sock_rudp_vector.clear();
    m_rw_locker.unlock();
}

void RudpMgr::set_sink(RudpMgrSink * sink)
{
    if (NULL == (m_rudp_mgr_sink = sink))
    {
        printf("rudp manager sink must been set\n");
        exit(1);
    }
}

void RudpMgr::run()
{
    int error_no = 0;
    if (0 != (error_no = pthread_create(&m_recv_thread, NULL, recv_data_func, this)))
    {
        printf("pthread_create recv_data_thread error: %s\n", strerror(error_no));
        exit(1);
    }
    if (0 != (error_no = pthread_create(&m_send_thread, NULL, send_data_func, this)))
    {
        printf("pthread_create recv_data_thread error: %s\n", strerror(error_no));
        exit(1);
    }
    if (0 != (error_no = pthread_create(&m_handle_thread, NULL, handle_data_func, this)))
    {
        printf("pthread_create recv_data_thread error: %s\n", strerror(error_no));
        exit(1);
    }
    m_is_running = true;
}

bool RudpMgr::send_data(uint32_t unique_id, unsigned char * data, uint16_t len, bool reliable)
{
    m_rw_locker.rdlock();
    Rudp * prudp = NULL;
    vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
    while (m_sock_rudp_vector.end() != vsr_iter)
    {
        if (NULL != vsr_iter->prudp && vsr_iter->prudp->get_unique_id() == unique_id)
        {
            prudp = vsr_iter->prudp;
            break;
        }
    }
    bool ret = (NULL != prudp && prudp->send_data(data, len, reliable));
    m_rw_locker.unlock();

    return(ret);
}

bool RudpMgr::handle_data(uint32_t unique_id, unsigned char * data, uint16_t len)
{
    assert(NULL != m_rudp_mgr_sink);
    return(NULL != m_rudp_mgr_sink && m_rudp_mgr_sink->handle_data(unique_id, data, len));
}

void RudpMgr::create_rudp(const char * host, uint16_t port)
{
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port);

    if (inet_pton(AF_INET, host, &servaddr.sin_addr) <= 0)
    {
        perror("inet_pton error");
        exit(1);
    }

    int connfd = -1;

    if (-1 == (connfd = socket(AF_INET, SOCK_DGRAM, 0)))
    {
        perror("socket error");
        exit(1);
    }

    if (-1 == connect(connfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))
    {
        perror("connect error");
        exit(1);
    }

    int send_times = 30;
    while (--send_times >= 0)
    {
        if (-1 == write(connfd, NULL, 0))
        {
            perror("write error");
            exit(1);
        }

        if (readable_timeout(connfd, 1))
        {
            break;
        }
    }

    if (send_times < 0)
    {
        printf("can not connect to server, maybe it is too busy)\n");
        exit(1);
    }

    const int buff_size = 576;
    char buff[buff_size];
    int pkg_size = 0;
    if (-1 == (pkg_size = read(connfd, buff, buff_size - 1)))
    {
        perror("read error");
        if (ECONNREFUSED == errno)
        {
            printf("server maybe terminated\n");
        }
        exit(1);
    }

    buff[pkg_size] = '\0';
    char * ptr = strrchr(buff, ':');
    if (NULL == ptr)
    {
        printf("recv exception address message: %s\n", buff);
        exit(1);
    }
    *ptr = '\0';

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(atoi(ptr + 1));

    if (inet_pton(AF_INET, buff, &servaddr.sin_addr) <= 0)
    {
        perror("inet_pton error");
        exit(1);
    }

    if (-1 == connect(connfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))
    {
        perror("connect error");
        exit(1);
    }

    m_mutex_locker.lock();
    uint32_t unique_id = 0;
    if (m_unique_id_vector.size() >= m_unique_id_vector.max_size() - 1)
    {
        printf("can not support more rudp\n");
        exit(1);
    }
    do
    {
        unique_id = m_unique_id_creator++;
    } while (0 == unique_id || 
             m_unique_id_vector.end() != 
             find(m_unique_id_vector.begin(), m_unique_id_vector.end(), unique_id));

    Rudp * prudp = new Rudp(this, connfd, unique_id);
    if (NULL == prudp)
    {
        printf("new rudp failed\n");
        exit(1);
    }

    m_unique_id_vector.push_back(unique_id);
    m_mutex_locker.unlock();

    sock_rudp sr = { connfd, prudp };

    m_rw_locker.wrlock();
    m_sock_rudp_vector.push_back(sr);
    m_rw_locker.unlock();

    FD_SET(connfd, &m_rset);
    if (m_maxrfdp1 < connfd + 1)
    {
        m_maxrfdp1 = connfd + 1;
    }

    assert(NULL != m_rudp_mgr_sink);
    if (NULL != m_rudp_mgr_sink)
    {
        m_rudp_mgr_sink->onconnect(unique_id);
    }
}

void RudpMgr::destroy_rudp(uint32_t unique_id)
{
    destroy_rudp(unique_id, false);
}

void RudpMgr::destroy_rudp(uint32_t unique_id, bool is_locked)
{
    int connfd = -1;

    if (!is_locked)
    {
        m_rw_locker.wrlock();
    }
    vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
    while (m_sock_rudp_vector.end() != vsr_iter)
    {
        if (NULL != vsr_iter->prudp && vsr_iter->prudp->get_unique_id() == unique_id)
        {
            connfd = vsr_iter->connfd;
            FD_CLR(connfd, &m_rset);
            close(connfd);
            delete vsr_iter->prudp;
            m_sock_rudp_vector.erase(vsr_iter);
            break;
        }
        else
        {
            ++vsr_iter;
        }
    }
    if (!is_locked)
    {
        m_rw_locker.unlock();
    }

    if (-1 == connfd)
    {
        return;
    }

    m_mutex_locker.lock();
    map<string, int>::iterator msi_iter = m_address_socket_map.begin();
    while (m_address_socket_map.end() != msi_iter)
    {
        if (msi_iter->second == connfd)
        {
            m_address_socket_map.erase(msi_iter);
            break;
        }
        else
        {
            ++msi_iter;
        }
    }

    vector<uint32_t>::iterator vu_iter = find(m_unique_id_vector.begin(), m_unique_id_vector.end(), unique_id);
    if (m_unique_id_vector.end() != vu_iter)
    {
        m_unique_id_vector.erase(vu_iter);
    }
    m_mutex_locker.unlock();

    assert(NULL != m_rudp_mgr_sink);
    if (NULL != m_rudp_mgr_sink)
    {
        m_rudp_mgr_sink->ondisconnect(unique_id);
    }
}

int RudpMgr::recv_data_thread()
{
    const int buff_size = 65535;
    char buff[buff_size];
    int pkg_size = 0;

    while (true)
    {
        if (m_maxrfdp1 <= 0)
        {
            sleep(1);
            continue;
        }

        int nready = 0;
        fd_set rset = m_rset;
        if (-1 == (nready = select(m_maxrfdp1, &rset, NULL, NULL, NULL)))
        {
            if (EINTR == errno)
            {
                continue;
            }
            else
            {
                perror("select error");
                exit(1);
            }
        }

        if (-1 != m_listenfd && FD_ISSET(m_listenfd, &rset))
        {
            struct sockaddr_in peer_addr;
            socklen_t peer_len = sizeof(peer_addr);

            if (-1 == (pkg_size = recvfrom(m_listenfd, buff, buff_size, 0,
                                           (struct sockaddr *)&peer_addr, &peer_len)))
            {
                perror("recvfrom error");
                exit(1);
            }

            const char * paddr = NULL;
            if (NULL == (paddr = inet_ntoa(peer_addr.sin_addr)))
            {
                perror("inet_ntoa error");
                exit(1);
            }
            snprintf(buff, buff_size, "%s:%d", paddr, ntohs(peer_addr.sin_port));

            string peer_address(buff);

            int connfd = -1;
            m_mutex_locker.lock();
            map<string, int>::iterator msi_iter = m_address_socket_map.find(peer_address);
            if (m_address_socket_map.end() == msi_iter)
            {
                if (-1 == (connfd = socket(AF_INET, SOCK_DGRAM, 0)))
                {
                    perror("socket error");
                    exit(1);
                }

                if (-1 == connect(connfd, (struct sockaddr *)&peer_addr, peer_len))
                {
                    perror("connect error");
                    exit(1);
                }

                uint32_t unique_id = 0;
                if (m_unique_id_vector.size() >= m_unique_id_vector.max_size() - 1)
                {
                    printf("can not create more Rudp\n");
                    exit(1);
                }
                do
                {
                    unique_id = m_unique_id_creator++;
                } while (0 == unique_id || 
                         m_unique_id_vector.end() != 
                         find(m_unique_id_vector.begin(), m_unique_id_vector.end(), unique_id));

                Rudp * prudp = new Rudp(this, connfd, unique_id);
                if (NULL == prudp)
                {
                    printf("new rudp failed\n");
                    exit(1);
                }

                m_unique_id_vector.push_back(unique_id);
                m_address_socket_map[peer_address] = connfd;
                m_mutex_locker.unlock();

                sock_rudp sr = { connfd, prudp };

                m_rw_locker.wrlock();
                m_sock_rudp_vector.push_back(sr);
                m_rw_locker.unlock();

                FD_SET(connfd, &m_rset);
                if (m_maxrfdp1 < connfd + 1)
                {
                    m_maxrfdp1 = connfd + 1;
                }

                assert(NULL != m_rudp_mgr_sink);
                if (NULL != m_rudp_mgr_sink)
                {
                    m_rudp_mgr_sink->onconnect(unique_id);
                }
            }
            else
            {
                connfd = msi_iter->second;
                m_mutex_locker.unlock();
                assert(-1 != connfd);
            }

            struct sockaddr_in local_addr;
            socklen_t local_len = sizeof(local_addr);
            if (-1 == getsockname(connfd, (struct sockaddr *)&local_addr, &local_len))
            {
                perror("getsockname error");
                exit(1);
            }
            if (NULL == (paddr = inet_ntoa(local_addr.sin_addr)))
            {
                perror("inet_ntoa error");
                exit(1);
            }
            snprintf(buff, buff_size, "%s:%d", paddr, ntohs(local_addr.sin_port));

            pkg_size = strlen(buff);
            if (-1 == sendto(m_listenfd, buff, pkg_size, 0, (struct sockaddr *)&peer_addr, peer_len))
            {
                perror("sendto error");
                exit(1);
            }

            if (--nready <= 0)
            {
                continue;
            }
        }

        m_rw_locker.rdlock();
        vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
        while (m_sock_rudp_vector.end() != vsr_iter)
        {
            int connfd = vsr_iter->connfd;
            Rudp * prudp = vsr_iter->prudp;

            if (connfd < 0 || NULL == prudp)
            {
                assert(false);
                exit(1);
            }

            if (FD_ISSET(connfd, &rset))
            {
                if (-1 == (pkg_size = read(connfd, buff, buff_size)))
                {
                    prudp->kill();
                }
                else
                {
                    prudp->recv_data((unsigned char *)buff, pkg_size);
                }

                if (--nready <= 0)
                {
                    break;
                }
            }

            ++vsr_iter;
        }
        m_rw_locker.unlock();
    }

    return(0);
}

int RudpMgr::send_data_thread()
{
    time_type last_send_heart_beat_time = getcurtime();

    while (true)
    {
        bool need_send_heart_beat_package = false;
        if (getcurtime() - last_send_heart_beat_time >= 1000)
        {
            need_send_heart_beat_package = true;
            last_send_heart_beat_time = getcurtime();
        }

        fd_set wset;
        FD_ZERO(&wset);
        int maxwfdp1 = -1;

        m_rw_locker.wrlock();
        for (int index = m_sock_rudp_vector.size() - 1; index >= 0; --index)
        {
            sock_rudp & sr = m_sock_rudp_vector[index];
            int connfd = sr.connfd;
            Rudp * prudp = sr.prudp;

            if (connfd < 0 || NULL == prudp)
            {
                assert(false);
                exit(1);
            }

            if (!prudp->is_alive())
            {
                destroy_rudp(prudp->get_unique_id(), true);
                continue;
            }

            if (need_send_heart_beat_package)
            {
                prudp->send_heart_beat_package();
            }

            if (prudp->has_data_to_send())
            {
                FD_SET(connfd, &wset);
                if (maxwfdp1 < connfd + 1)
                {
                    maxwfdp1 = connfd + 1;
                }
            }
        }
        m_rw_locker.unlock();

        if (maxwfdp1 <= 0)
        {
            sleep(1);
            continue;
        }

        int nready = 0;
        if (-1 == (nready = select(maxwfdp1, NULL, &wset, NULL, NULL)))
        {
            if (EINTR == errno)
            {
                continue;
            }
            else
            {
                perror("select error");
                exit(1);
            }
        }

        m_rw_locker.rdlock();
        vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
        while (m_sock_rudp_vector.end() != vsr_iter)
        {
            int connfd = vsr_iter->connfd;
            Rudp * prudp = vsr_iter->prudp;

            if (connfd < 0 || NULL == prudp)
            {
                assert(false);
                exit(1);
            }

            if (FD_ISSET(connfd, &wset))
            {
                prudp->send_data();

                if (--nready <= 0)
                {
                    break;
                }
            }

            ++vsr_iter;
        }
        m_rw_locker.unlock();
    }

    return(0);
}

int RudpMgr::handle_data_thread()
{
    while (true)
    {
        m_rw_locker.rdlock();
        vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
        while (m_sock_rudp_vector.end() != vsr_iter)
        {
            int connfd = vsr_iter->connfd;
            Rudp * prudp = vsr_iter->prudp;

            if (connfd < 0 || NULL == prudp)
            {
                assert(false);
                exit(1);
            }

            prudp->analytic_data();

            ++vsr_iter;
        }
        m_rw_locker.unlock();
    }

    return(0);
}

rudpmgrsink.h:

#ifndef __RUDP_MANAGER_SINK_H__
#define __RUDP_MANAGER_SINK_H__


#include "types.h"

class RudpMgr;

class RudpMgrSink
{
public:
    RudpMgrSink(RudpMgr * mgr);
    virtual ~RudpMgrSink();

public:
    void create_rudp(const char * host, uint16_t port);
    void destroy_rudp(uint32_t unique_id);
    bool send_data(uint32_t unique_id, unsigned char * data, uint16_t len, bool reliable);

public:
    virtual void onconnect(uint32_t unique_id);
    virtual void ondisconnect(uint32_t unique_id);
    virtual bool handle_data(uint32_t conn, unsigned char * data, uint16_t len);

private:
    RudpMgr * m_rudp_mgr;
};


#endif

rudpmgrsink.cpp:

#include <cstdio>
#include <cstdlib>

#include "types.h"
#include "rudpmgr.h"
#include "rudpmgrsink.h"


RudpMgrSink::RudpMgrSink(RudpMgr * mgr) : m_rudp_mgr(mgr)
{
    if (NULL == m_rudp_mgr)
    {
        printf("rudp manager must been set\n");
        exit(1);
    }
    m_rudp_mgr->set_sink(this);
}

RudpMgrSink::~RudpMgrSink()
{
    
}

void RudpMgrSink::create_rudp(const char * host, uint16_t port)
{
    if (NULL != m_rudp_mgr)
    {
        m_rudp_mgr->create_rudp(host, port);
    }
}

void RudpMgrSink::destroy_rudp(uint32_t unique_id)
{
    if (NULL != m_rudp_mgr)
    {
        m_rudp_mgr->destroy_rudp(unique_id);
    }
}

bool RudpMgrSink::send_data(uint32_t unique_id, unsigned char * data, uint16_t len, bool reliable)
{
    return(NULL != m_rudp_mgr && m_rudp_mgr->send_data(unique_id, data, len, reliable));
}

void RudpMgrSink::onconnect(uint32_t unique_id)
{
    
}

void RudpMgrSink::ondisconnect(uint32_t unique_id)
{
    
}

bool RudpMgrSink::handle_data(uint32_t conn, unsigned char * data, uint16_t len)
{
    return(true);
}

test.cpp:

#include <cstdio>
#include <unistd.h>

#include "rudpmgr.h"
#include "rudpmgrsink.h"


class Sink : public RudpMgrSink
{
public:
    Sink(RudpMgr * mgr) : RudpMgrSink(mgr)
    {
        
    }
};

int main()
{
    RudpMgr * p = new RudpMgr;
    Sink s(p);
    p->run();
    sleep(1);
    delete p;
    printf("fine\n");
    return(0);
}

makefile_test:

objects=test.o rudpmgr.o rudp.o rudpmgrsink.o common.o lock.o
test:$(objects)
	g++ -o test $(objects) -lpthread

test.o:test.cpp rudpmgr.h rudpmgrsink.h
	g++ -c test.cpp
rudpmgr.o:rudpmgr.cpp rudpmgr.h rudp.h rudpmgrsink.h types.h common.h lock.h
	g++ -c rudpmgr.cpp
rudp.o:rudp.cpp rudp.h rudpmgr.h nodes.hpp lock.h
	g++ -c rudp.cpp
rudpmgrsink.o:rudpmgrsink.cpp rudpmgrsink.h rudpmgr.h types.h
	g++ -c rudpmgrsink.cpp
common.o:common.cpp common.h types.h
	g++ -c common.cpp
lock.o:lock.cpp lock.h
	g++ -c lock.cpp

rebuild:clean test

clean:  
	-rm test $(objects)


command.h:

#ifndef __COMMAND_H__
#define __COMMAND_H__


enum
{
    cmd_reverse
};


#endif

testclient.h:

#ifndef __TEST_CLIENT_H__
#define __TEST_CLIENT_H__


#include <string>
using std::string;

#include "command.h"
#include "rudpmgrsink.h"

class TestClient : public RudpMgrSink
{
public:
    TestClient(RudpMgr * mgr, const char * host, uint16_t port);
    virtual ~TestClient();

public:
    virtual void onconnect(uint32_t unique_id);
    virtual void ondisconnect(uint32_t unique_id);
    virtual bool handle_data(uint32_t conn, unsigned char * data, uint16_t len);

public:
    bool handle_reverse_string_response(unsigned char * data, uint16_t len);

public:
    bool send_reverse_string_request(const char * str);

private:
    string m_host;
    uint16_t m_port;
    uint32_t m_unique_id;
};

#endif

testclient.cpp:

#include <cstdio>
#include <cassert>
#include <cstring>

#include "testclient.h"

TestClient::TestClient(RudpMgr * mgr, const char * host, uint16_t port)
 : RudpMgrSink(mgr), m_host(host), m_port(port), m_unique_id(0)
{
    create_rudp(m_host.c_str(), m_port); /* connect to host:port */
}

TestClient::~TestClient()
{
    if (0 != m_unique_id)
    {
        destroy_rudp(m_unique_id); /* disconnect with host:port */
    }
}

void TestClient::onconnect(uint32_t unique_id)
{
    if (0 == m_unique_id)
    {
        m_unique_id = unique_id; /* get connection handle */
    }
    else
    {
        assert(false);
        destroy_rudp(unique_id);  /* disconnect with unknown peer */
    }
}

void TestClient::ondisconnect(uint32_t unique_id)
{
    if (m_unique_id == unique_id)
    {
        m_unique_id = 0;
        create_rudp(m_host.c_str(), m_port); /* reconnect to host:port */
    }
}

bool TestClient::handle_data(uint32_t unique_id, unsigned char * data, uint16_t len)
{
    unsigned char cmd = data[0];
    data += 1;
    len -= 1;

    switch (cmd)
    {
        case cmd_reverse:
        {
            return(handle_reverse_string_response(data, len));
        }
        default:
        {
            return(false);
        }
    }    
}

bool TestClient::handle_reverse_string_response(unsigned char * data, uint16_t len)
{
    fprintf(stderr, "reverse string: %s\n", (char *)data);
    return(true);
}

bool TestClient::send_reverse_string_request(const char * str)
{
    if (0 == m_unique_id)
    {
        create_rudp(m_host.c_str(), m_port); /* connect to host:port */
        return(false);
    }

    uint16_t len = strlen(str);
    if (len > 65535 - sizeof(unsigned char) + sizeof(uint16_t))
    {
        return(false);
    }

    unsigned char buff[65535];
    buff[0] = (unsigned char)cmd_reverse;
    memcpy(buff + 1, str, len + 1);
    len += 2;

    return(send_data(m_unique_id, buff, len, true));
}

client.cpp:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <errno.h>
#include <unistd.h>

#include "rudpmgr.h"
#include "testclient.h"

int main()
{
    RudpMgr * prudpmgr = new RudpMgr();
    TestClient client(prudpmgr, "127.0.0.1", 10000);
    prudpmgr->run();

    char  buff[4096] = { 0 };
    while (fgets(buff, 4095, stdin) != NULL)
    {
        int len = strlen(buff);
        if (len > 0 && ('\r' == buff[len - 1] || '\n' == buff[len - 1]))
        {
            buff[len - 1] = '\0';
        }
        client.send_reverse_string_request(buff);
    }
    if (ferror(stdin)) {
        perror("fget error");
        exit(1);
    }

    sleep(5);
    delete prudpmgr;

    printf("test over\n");

    return(0);
}

makefile_client:

objects=client.o testclient.o rudpmgr.o rudp.o rudpmgrsink.o common.o lock.o
client:$(objects)
	g++ -o client $(objects) -lpthread

client.o:client.cpp rudpmgr.h testclient.h
	g++ -c client.cpp
testclient.o:testclient.cpp testclient.h
	g++ -c testclient.cpp
rudpmgr.o:rudpmgr.cpp rudpmgr.h rudp.h rudpmgrsink.h types.h common.h lock.h
	g++ -c rudpmgr.cpp
rudp.o:rudp.cpp rudp.h rudpmgr.h nodes.hpp lock.h
	g++ -c rudp.cpp
rudpmgrsink.o:rudpmgrsink.cpp rudpmgrsink.h rudpmgr.h types.h
	g++ -c rudpmgrsink.cpp
common.o:common.cpp common.h types.h
	g++ -c common.cpp
lock.o:lock.cpp lock.h
	g++ -c lock.cpp

rebuild:clean client

clean:  
	-rm client $(objects)


testserver.h:

#ifndef __TEST_SERVER_H__
#define __TEST_SERVER_H__


#include "command.h"
#include "rudpmgrsink.h"

class TestServer : public RudpMgrSink
{
public:
    TestServer(RudpMgr * mgr);
    virtual ~TestServer();

public:
    virtual void onconnect(uint32_t unique_id);
    virtual void ondisconnect(uint32_t unique_id);
    virtual bool handle_data(uint32_t conn, unsigned char * data, uint16_t len);

public:
    bool handle_reverse_string_request(uint32_t unique_id, unsigned char * data, uint16_t len);

public:
    bool send_reverse_string_response(uint32_t unique_id, unsigned char * data, uint16_t len);
};

#endif

testserver.cpp:

#include <cstring>

#include "testserver.h"

TestServer::TestServer(RudpMgr * mgr) : RudpMgrSink(mgr)
{
    
}

TestServer::~TestServer()
{
    
}

void TestServer::onconnect(uint32_t unique_id)
{
    
}

void TestServer::ondisconnect(uint32_t unique_id)
{
    
}

bool TestServer::handle_data(uint32_t unique_id, unsigned char * data, uint16_t len)
{
    unsigned char cmd = data[0];
    data += 1;
    len -= 1;

    switch (cmd)
    {
        case cmd_reverse:
        {
            return(handle_reverse_string_request(unique_id, data, len));
        }
        default:
        {
            return(false);
        }
    }    
}

bool TestServer::handle_reverse_string_request(uint32_t unique_id, unsigned char * data, uint16_t len)
{
    for (int index = 0; index < len / 2; ++index)
    {
        unsigned char temp = data[index];
        data[index] = data[len - 2 - index];
        data[len - 2 - index] = temp;
    }
    return(send_reverse_string_response(unique_id, data, len));
}

bool TestServer::send_reverse_string_response(uint32_t unique_id, unsigned char * data, uint16_t len)
{
    if (0 == unique_id)
    {
        return(false);
    }

    if (len > 65535 - sizeof(unsigned char) + sizeof(uint16_t))
    {
        return(false);
    }

    unsigned char buff[65535];
    buff[0] = (unsigned char)cmd_reverse;
    len += sizeof(unsigned char);
    memcpy(buff + 1, data, len);
    len += 1;
    return(send_data(unique_id, buff, len, true));
}

server.cpp:

#include <cstdio>
#include <cstdlib>
#include <unistd.h>

#include "rudpmgr.h"
#include "testserver.h"

int main()
{
    RudpMgr * prudpmgr = new RudpMgr(10000);
    TestServer server(prudpmgr);
    prudpmgr->run();

    while (true)
    {
        pause();
    }

    delete prudpmgr;

    printf("test over\n");

    return(0);
}

makefile_server:

objects=server.o testserver.o rudpmgr.o rudp.o rudpmgrsink.o common.o lock.o
server:$(objects)
	g++ -o server $(objects) -lpthread

server.o:server.cpp rudpmgr.h testserver.h
	g++ -c server.cpp
testserver.o:testserver.cpp testserver.h
	g++ -c testserver.cpp
rudpmgr.o:rudpmgr.cpp rudpmgr.h rudp.h rudpmgrsink.h types.h common.h lock.h
	g++ -c rudpmgr.cpp
rudp.o:rudp.cpp rudp.h rudpmgr.h nodes.hpp lock.h
	g++ -c rudp.cpp
rudpmgrsink.o:rudpmgrsink.cpp rudpmgrsink.h rudpmgr.h types.h
	g++ -c rudpmgrsink.cpp
common.o:common.cpp common.h types.h
	g++ -c common.cpp
lock.o:lock.cpp lock.h
	g++ -c lock.cpp

rebuild:clean server

clean:  
	-rm server $(objects)




评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值