rudp

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

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(uint
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值