精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
网站首页
技术服务
技术中心
开源优势
英语优势
服务流程
典型客户
服务分类
软件开发
商业项目优势
产品列表
服务流程
典型客户
软件开发培训
在线教育
连锁培训
高校合作
兴趣
科研
就业
企业合作
人才委托培训
HR整体外包
关于我们
公司理念
公司荣誉
公司架构
人才招聘
视频下载
软件开发培训高品质源自卓越软件开发能力
高端企业级软件开发培训模式,承诺掌握软件开发工作经验
软件开发在线教育品质出众和软件开发培训实地面授效果一致
软件开发培训诚信经营
当前位置:
锐英源
/
开源技术
/
基于UDP的数据传输协议UDT
/ UDT源码剖析 UDT自带例程sendfile注释
服务方向
人工智能数据处理
人工智能培训
kaldi数据准备
小语种语音识别
语音识别标注
语音识别系统
语音识别转文字
kaldi开发技术服务
软件开发
运动控制卡上位机
机械加工软件
软件开发培训
Java 安卓移动开发
VC++
C#软件
汇编和破解
驱动开发
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft
UDT源码剖析(一):UDT自带例程sendfile注释
#ifndef WIN32
#include <cstdlib>
#include <netdb.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include <fstream>
#include <iostream>
#include <cstring>
#include <udt.h>
using namespace std;
#ifndef WIN32
void* sendfile(void*);
#else
DWORD WINAPI sendfile(LPVOID);
#endif
int main(int argc, char* argv[])
{
//usage: sendfile [server_port]
if ((2 < argc) || ((2 == argc) && (0 == atoi(argv[1]))))
{
cout << "usage: sendfile [server_port]" << endl;
return 0;
}
// use this function to initialize the UDT library
// 初始化UDT库
UDT::startup();
// 地址信息提示
addrinfo hints;
// 实际使用的地址信息指针
addrinfo* res;
// 内存初始化,全部置为0
memset(&hints, 0, sizeof(struct addrinfo));
// 如上表所示,ai_flagsde值范围为0~7,取决于程序如何设置3个标志位,
// 比如设置ai_flags为 “AI_PASSIVE|AI_CANONNAME”,ai_flags值就为3。三个参数的含义分别为:
// (1)AI_PASSIVE当此标志置位时,表示调用者将在bind()函数调用中使用返回的地址结构。当此标志不置位时,表示将在connect()函数调用中使用。
// 当节点名位NULL,且此标志置位,则返回的地址将是通配地址。如果节点名NULL,且此标志不置位,则返回的地址将是回环地址。
// (2)AI_CANNONAME当此标志置位时,在函数所返回的第一个addrinfo结构中的ai_cannoname成员中,
// 应该包含一个以空字符结尾的字符串,字符串的内容是节点名的正规名。
// (3)AI_NUMERICHOST当此标志置位时,此标志表示调用中的节点名必须是一个数字地址字符串。
hints.ai_flags = AI_PASSIVE;
// AF_UNIX(本机通信)
// AF_INET(TCP/IP – IPv4)
// AF_INET6(TCP/IP – IPv6)
hints.ai_family = AF_INET;
// SOCK_STREAM: 提供面向连接的稳定数据传输,即TCP协议。
// OOB: 在所有数据传送前必须使用connect()来建立连接状态。
// SOCK_DGRAM: 使用不连续不可靠的数据包连接。
// SOCK_SEQPACKET: 提供连续可靠的数据包连接。
// SOCK_RAW: 提供原始网络协议存取。
// SOCK_RDM: 提供可靠的数据包连接。
// SOCK_PACKET: 与网络驱动程序直接通信。
//////////// 注:此处的SOCK_STREAM并不是表示UDT将会使用TCP类型的Socket,在底层将会转化为UDT_STREAM
//////////// 并且在UDT中仅支持SOCK_STREAM和SOCK_DGRAM,分别对应UDT_STREAM和UDT_DGRAM
hints.ai_socktype = SOCK_STREAM;
// 默认服务端口
string service("9000");
if (2 == argc)
service = argv[1];
// 根据地址信息提示分配实际可用的地址信息
if (0 != getaddrinfo(NULL, service.c_str(), &hints, &res))
{
cout << "illegal port number or port is busy.\n" << endl;
return 0;
}
// 根据实际使用的地址信息创建一个UDT的socket
// 此处实际上最终调用了CUDTUnited的newSocket,第一个参数会被直接设置到CUDT的m_iIPversion,第二个参数会被映射为UDT的连接类型,第三个参数被忽略,没有实际意义
// Gu说了函数原型尽量保持与BSD的Socket一致,因此一些对系统没意义的参数也被照搬了进来……
UDTSOCKET serv = UDT::socket(res->ai_family, res->ai_socktype, res->ai_protocol);
// Windows UDP issue
// For better performance, modify HKLM\System\CurrentControlSet\Services\Afd\Parameters\FastSendDatagramThreshold
// Windows下的UDP的问题
// 如果想要提高效率,可以修改注册表HKLM\System\CurrentControlSet\Services\Afd\Parameters\FastSendDatagramThreshold
#ifdef WIN32
int mss = 1052;
// 第一个参数为要设置的UDTSocket
// 第二个参数0是会被忽略的,没有实际意义
// 第三个参数为要设置的参数,有以下几种选项、来自enum UDTOpt:
// UDT_MSS 最大传输单位
// UDT_SNDSYN 是否阻塞发送
// UDT_RCVSYN 是否阻塞接收
// UDT_CC 自定义拥塞控制算法
// UDT_FC 窗口大小
// UDT_SNDBUF 发送队列缓冲最大值
// UDT_RCVBUF UDT接收缓冲大小
// UDT_LINGER 关闭时等待数据发送完成
// UDP_SNDBUF UDP发送缓冲大小
// UDP_RCVBUF UDP接收缓冲大小
// UDT_RENDEZVOUS 会合连接模式
// UDT_SNDTIMEO send()超时
// UDT_RCVTIMEO recv()超时
// UDT_REUSEADDR 复用一个已存在的端口或者创建一个新的端口
// UDT_MAXBW 当前连接可以使用的最大带宽(bytes per second)
// 第四个参数是参数值
// 第五个参数为参数值长度,在底层也会被忽略,没有意义
UDT::setsockopt(serv, 0, UDT_MSS, &mss, sizeof(int));
#endif
// 绑定端口,第一个参数为Socket,第二个为绑定地址,第三个为地址长度(底层用来判断是否符合IPv4、IPv6标准的长度)
if (UDT::ERROR == UDT::bind(serv, res->ai_addr, res->ai_addrlen))
{
cout << "bind: " << UDT::getlasterror().getErrorMessage() << endl;
return 0;
}
// 释放通过getaddrinfo分配的地址信息
freeaddrinfo(res);
cout << "server is ready at port: " << service << endl;
// 开始监听,第一个参数为Socket,第二个参数为队列中允许的最大连接数
UDT::listen(serv, 10);
// 客户端地址信息
sockaddr_storage clientaddr;
// 地址信息数据长度
int addrlen = sizeof(clientaddr);
// 捕获连接的Socket
UDTSOCKET fhandle;
while (true)
{
// 接受连接请求,第一个参数为Socket,第二个参数为请求方地址信息,第三个参数为地址信息长度,
// 第二个和第三个参数必须分配好地址空间,才能返回信息
if (UDT::INVALID_SOCK == (fhandle = UDT::accept(serv, (sockaddr*)&clientaddr, &addrlen)))
{
cout << "accept: " << UDT::getlasterror().getErrorMessage() << endl;
return 0;
}
// 通过getnameinfo()将地址信息转换为节点地址、端口信息
char clienthost[NI_MAXHOST];
char clientservice[NI_MAXSERV];
getnameinfo((sockaddr *)&clientaddr, addrlen, clienthost, sizeof(clienthost), clientservice, sizeof(clientservice), NI_NUMERICHOST|NI_NUMERICSERV);
cout << "new connection: " << clienthost << ":" << clientservice << endl;
// 连接成功后启动sendfile线程,传入捕获到的Socket,这里使用了拷贝构造创建一个新的对象,使得fhandle本身的使用不会受到线程的影响
#ifndef WIN32
pthread_t filethread;
pthread_create(&filethread, NULL, sendfile, new UDTSOCKET(fhandle));
pthread_detach(filethread);
#else
CreateThread(NULL, 0, sendfile, new UDTSOCKET(fhandle), 0, NULL);
#endif
}
// 关闭监听Socket
UDT::close(serv);
// use this function to release the UDT library
// 释放UDT库
UDT::cleanup();
return 0;
}
#ifndef WIN32
void* sendfile(void* usocket)
#else
DWORD WINAPI sendfile(LPVOID usocket)
#endif
{
// 获取Socket,并清除原传入的Socket
UDTSOCKET fhandle = *(UDTSOCKET*)usocket;
delete (UDTSOCKET*)usocket;
// aquiring file name information from client
// 从请求端获得文件名
char file[1024];
int len;
// 接收一个数据包,内容为一个int值,长度为int的长度,数值保存在len中
// 第一个参数为Socket,第二个参数为数据保存地址,第三个参数为数据长度,第四个参数底层会忽略,没有意义
if (UDT::ERROR == UDT::recv(fhandle, (char*)&len, sizeof(int), 0))
{
cout << "recv: " << UDT::getlasterror().getErrorMessage() << endl;
return 0;
}
// 开始接收信息,通过上面获得的长度来判断信息的大小
if (UDT::ERROR == UDT::recv(fhandle, file, len, 0))
{
cout << "recv: " << UDT::getlasterror().getErrorMessage() << endl;
return 0;
}
// 给接收到的字符串加结束符
file[len] = '\0';
// open the file
// 打开请求方指定的文件,以二进制方式读取打开
fstream ifs(file, ios::in | ios::binary);
// 让文件指针定位到文件末尾
ifs.seekg(0, ios::end);
// 获得文件大小
int64_t size = ifs.tellg();
// 让文件指针定位到文件开头
ifs.seekg(0, ios::beg);
// send file size information
// 向请求方发送文件长度
// 第一个参数为Socket,第二个参数为数据地址,第三个参数为数据长度,第四个参数会被底层忽略,没有意义
if (UDT::ERROR == UDT::send(fhandle, (char*)&size, sizeof(int64_t), 0))
{
cout << "send: " << UDT::getlasterror().getErrorMessage() << endl;
return 0;
}
// 初始采样,内容见CPerfMon
UDT::TRACEINFO trace;
UDT::perfmon(fhandle, &trace);
// send the file
// 偏移量为0,开始发送文件
// 第一个参数为Socket,第二个参数为文件流,第三个参数为偏移量,第四个参数为文件大小
int64_t offset = 0;
if (UDT::ERROR == UDT::sendfile(fhandle, ifs, offset, size))
{
cout << "sendfile: " << UDT::getlasterror().getErrorMessage() << endl;
return 0;
}
// 获取采样信息,内容见CPerfMon
// 得出传输效率
UDT::perfmon(fhandle, &trace);
cout << "speed = " << trace.mbpsSendRate << "Mbits/sec" << endl;
// 关闭连接Socket
UDT::close(fhandle);
// 关闭文件流
ifs.close();
#ifndef WIN32
return NULL;
#else
return 0;
#endif
}
友情链接
汕头招聘网
|
山东招聘网
|
郑州教育培训
|
软件下载
版权所有 Copyright(c)2004-2024 锐英源软件
统一社会信用代码:91410105098562502G 豫ICP备08007559号 最佳分辨率 1440*900
地址:郑州市金水区文化路97号郑州大学北区院内南门附近