更新日志
11/06/2021
- 1.增加IPV6
- 2.ipv6通過windows10初步測試
- 3.ipv6包括: 接收和發送
- 5.增加錯誤代碼接口
- 6.本機IPv6截圖
- 7.編譯通過截圖
- 8.ipv6測試結果
30/05/2021
1.增加IPv6,待測
2.全部改為Unicode編碼, 無簽名
23-05-2021
1.模塊內部增加優化
15/12/2020
- cmake重新配置,改為支持modern cmake
- 創建cmake文件夾,並創建spdlog.cmake文件
- 類的成員函數和成員變量重命名
11/06/2021
- 增加IPV6
- ipv6通過windows10初步測試
3.ipv6包括: 接收和發送
5.增加錯誤代碼接口
30/05/2021
1.增加IPv6,待測
2.全部改為Unicode編碼, 無簽名
簡介
- 1.這是一個使用C++11語法封裝的UDP,包括: ipv4 和 ipv6
- 2.ipv4支持: 單播、組播、廣播; linux + windows10測試通過,接收和發送均成功
- 3.ipv6通過windows10初步測試。收發均成功; 組播待測
- 5.支持接收和發送
- 6.使用cmake管理的項目
- 7.提供了調用范例
- 8.Linux支持仔細測試,最近比較忙。 后期更新
- 9.歡迎留言指導
接口分類
針對使用場景: 初始化, 發送, 接收, 關閉, 如果不接收, 則只有3個接口。 接口函數返回值后面再更新
使用
接收
接收需要重載 iudp.h中的類irecv_data的on_recv_data_函數。 on_recv_data_原型如下:
/// --------------------------------------------------------------------------------
/// @brief: 接收函數,
/// @param: const unsigned char * pdata_recv - 接收的數據
/// @param: const unsigned int recv_data_len - 接收數據長度
/// @return: void
///
/// --------------------------------------------------------------------------------
virtual void on_recv_data_(const unsigned char *pdata_recv, const unsigned int recv_data_len) = 0;
接收繼承范例
- 你可以在 example/main.cc 中找到下面的代碼
- 類my_udp繼承了類irecv_data類, 並實現函數on_recv_data_
class my_udp : public irecv_data
{
public:
/// ......
/// ......
/// you must override this function to recv data
void on_recv_data_(const unsigned char *pdata_recv, const unsigned int recv_data_len)
{
/// -------------------------------------------------------------------------------
/// 1. recv data
std::cout << "\n --------------AAAAAA data length = " << recv_data_len << "\n";
for (unsigned int i = 0; i < recv_data_len; i++)
{
if (i == 10)
std:: cout << "\n";
std::cout << pdata_recv[i] << ", ";
}
std::cout << "\n";
}
/// ....
當接收到數據,底層會調用該函數
接收要注意
- 如果需要接收數據,接口類 iudp 的接口 init_ 的第二個參數需要傳遞繼承自 接口類irecv_data的 on_recv_data_ 接口
- 如果不接收數據,接口類 iudp 的接口 init_ 的第二個參數傳遞 NULL(或nullptr)即可, 也不需要繼承 接口類irecv_data
接口類iudp
- iudp提供了udp的初始化、發送數據和關閉,提供了接口 error_id_() 獲取錯誤代碼
- 接口返回值詳見代碼(代碼寫的比較詳細了)
- 接口盡量設計的簡潔
代碼
/// ----------------------------------------------------------------------------
/// @brief: UDP接口類
/// ----------------------------------------------------------------------------
class iudp
{
public:
virtual ~iudp(){}
/// ------------------------------------------------------------
/// @brief:初始化
/// @param: const udp_param & param - 初始化參數
/// @param: irecv_data * pfunc_recv - 接收對象
/// @return: int
/// 0 - 成功
/// -1 - 失敗,param.socket_version_ 傳遞錯誤
/// --------------------------------------------------------------
/// ipv4和ipv6錯誤, 請調用error_id_()獲取錯誤代碼
/// 1 - 失敗, 端口為0
/// 2 - 失敗, 套接字創建失敗
/// 3 - 失敗,設置發送超時失敗
/// 5 - 失敗, 設置接收超時失敗
/// 6 - 失敗, 設置發送緩沖失敗
/// 7 - 失敗,設置接收緩沖失敗
/// 8 - 失敗,設置地址寵用失敗
/// 9 - 失敗, 綁定套接字失敗
/// 10 、11、12 - 失敗, 設置套接字 組播屬性失敗
/// 13 - 失敗,設置廣播失敗
/// 15 - 失敗,param._cast_type參數值傳遞錯誤
/// ------------------------------------------------------------
virtual int init_(const udp_param& param, irecv_data* pfunc_recv /* = nullptr */) = 0;
/// ------------------------------------------------------------
/// @brief:發送數據
/// @param: const unsigned char * psend - 待發送數據
/// @param: const unsigned int len_send - 待發送數據長度
/// @return: int
/// -1 - 失敗。初始化socket版本錯誤
/// 0 - 成功
/// 1 - 失敗, 參數【psend】為空或 【len_max_send】等於0 或則len_max_send大於發送緩沖區長度(10k)
/// 2 - 失敗,套接字創建失敗
/// 3 - 失敗, 發送數據失敗, 請調用error_id_()
/// ------------------------------------------------------------
virtual int send_(const unsigned char* psend, const unsigned int send_len) = 0;
/// --------------------------------------------------------------------------------
/// @brief: 關閉
/// @return: int
/// 0 - 成功
/// 其他, 失敗
/// --------------------------------------------------------------------------------
virtual int shutdown_() = 0;
/// ------------------------------------------------------------
/// @brief:返回錯誤ID
/// @return: int
///
/// ------------------------------------------------------------
virtual int error_id_() = 0;
};
創建和銷毀
創建
- 調用 iudp.h 中的 udp_create_() 可創建iudp。
- 函數說明
/// --------------------------------------------------------------------------------
/// @brief: 創建 udp對象
/// @return: lib_udp *
/// NULL- 創建失敗
/// != null - 成功
/// --------------------------------------------------------------------------------
lib_udp_api iudp * udp_create_();
銷毀
- 調用 iudp.h 中的udp_release_(iudp* pudp) 可銷毀udp_create_創建的對象
- 函數說明
/// --------------------------------------------------------------------------------
/// @brief: 釋放申請的資源, 內部釋放后,見其設置為NULL
/// @param: iudp * pudp - 來自【udp_create_】的創建結果
/// @return: lib_udp_api lib_udp *
/// pudp = NULL
/// --------------------------------------------------------------------------------
lib_udp_api iudp * udp_release_(iudp* pudp);
- 調用范例
pudp_ = udp_release_(pudp_);
項目地址
接口使用范例
- 你可以在 example/main.cc中找到下面的代碼
代碼
接收
/// to recv data, you must inherit udpsocket_recv class
class my_udp : public irecv_data
{
public:
/// constructor
my_udp()
{
if (NULL == pudp_)
pudp_ = udp_create_();//// std::unique_ptr<iudp>(lib_udp::udp_create_()).get();
}
/// deconstructor
virtual ~my_udp()
{
pudp_ = udp_release_(pudp_);
}
/// you must override this function to recv data
void on_recv_data_(const unsigned char *pdata_recv, const unsigned int recv_data_len)
{
/// -------------------------------------------------------------------------------
/// 1. recv data
std::cout << "\n --------------AAAAAA data length = " << recv_data_len << "\n";
for (unsigned int i = 0; i < recv_data_len; i++)
{
if (i == 10)
std:: cout << "\n";
std::cout << pdata_recv[i] << ", ";
}
std::cout << "\n";
}
/// -------------------------------------------------------------------------------
int init_(udp_param& param)
{
if (pudp_)
return pudp_->init_(param, this);
return -20000;
}
///
int send_(const char *psend, const int len_send)
{
if (pudp_)
return pudp_->send_((const unsigned char*)psend, len_send);
return -20000;
}
///
int shutdown_()
{
if (pudp_)
return pudp_->shutdown_();
return -20000;
}
int error_id_()
{
if (pudp_)
return pudp_->error_id_();
return -20000;
}
private:
iudp* pudp_ = NULL;
};
初始化、發送、關閉
/// -------------------------------------------------------------------------------
/// 1. to prepare params to initialize
udp_param param;
param._is_log_debug = false;
param._cast_type = lib_udp::udp_multi_cast;
param._port_dst = 10086;
param._recv_loop = true;
param.socket_version_ = kipv6;
#ifdef _WIN32
char arr_ipv4[] = "10.0.0.5";
#elif __linux__
char arr_ipv4[] = "192.168.15.129";
#else
char arr_ipv4[] = "10.1.1.3";
#endif///
std::cout << "local IP = " << arr_ipv4 << std::endl;
char arr_dst[] = "233.0.0.11";
//param.dest_ip_.value_ = std::string(arr_dst);
//param.local_ip_.value_ = std::string(arr_ipv4);
std::string str_ipv6;
int indexxxx = 0;
for (auto list_item : ip6_list)
{
str_ipv6 = list_item;
if (3 == indexxxx)
break;
++indexxxx;
}
param.dest_ip_.value_ = std::string("FF02::1");
param.local_ip_.value_ = str_ipv6;/// ip6_list.front();
/// -------------------------------------------------------------------------------
/// 1. to create
std::unique_ptr<my_udp> pmy_udp(new(std::nothrow) my_udp);
//my_udp* pmy_udp = new(std::nothrow) my_udp;
/// failure
if (!pmy_udp)
{
std::cout << "\n my_udp crated failure\n";
#ifdef _WIN32
system("pause");
#endif ///_WIN32
return 0;
}
/// -------------------------------------------------------------------------------
/// 2. to initialize udp
int ret = 0;
ret = pmy_udp->init_(param);
if (0 != ret)
{
std::cout << "\ninit error , id = " << ret << ", error id=" << pmy_udp->error_id_() << "\n\n";
ret = pmy_udp->shutdown_();
if (0 != ret)
std::cout << "\nshutdown error , id = " << ret << "\n";
#ifdef _WIN32
system("pause");
#endif ///_WIN32
return 0;
}
//pmy_udp->shutdown_();
////delete pmy_udp;
////pmy_udp = NULL;
//return 0;
std::cout << "\n init_ip4 success\n";
/// -------------------------------------------------------------------------------
/// 4. to send data
char arr[] = "1234567890";
for (int i = 0; i < 1; i++)
{
int send_len = pmy_udp->send_(arr, strlen(arr));
/// to output the result
std::cout << "udp send, send length = " << send_len << "\n";
std::this_thread::sleep_for(std::chrono::milliseconds(1000 * 1));
}
/// to recv data, it needs to rest
std::cout << "\n---------------------------main 1111----------------------------\n";
std::this_thread::sleep_for(std::chrono::milliseconds(1000 * 1));
std::cout << "\n---------------------------main 2222----------------------------\n";
pmy_udp->shutdown_();
std::cout << "\n---------------------------main 3333----------------------------\n";
std::cout << "\nudp has closed\n";