基于boost.asio库实现的类,可以发送,接收消息和文件。
参考文章:https://blog.csdn.net/sanmaoljh/article/details/52183723
1.发送消息时都会用数据包发送
2.数据包会用crc32校验码检验,若有误则置错误码为1
3.收到消息后会发送确认消息给发送端,发送端接收后核对,若错误码被置为1则重发数据包
4.算是UDP可靠传输
struct PackageHead{
unsigned int index; //包序号
unsigned int len; //数据字节数
unsigned int crc32val; //校验码
int errorFlag; //错误码
};
struct Package{
PackageHead head;
char buff[BUFFERSIZE];
};
class UDP
{
public:
UDP(socket_ptr s);
int send(char message[], endpoint ep); //发送消息
std::string receive(); //接收消息
long int sendFile(FILE *fp, endpoint ep); ///发送文件
void receiveFile(FILE *fp); //接收文件
private:
socket_ptr sock; //套接字
};
UDP::UDP(socket_ptr s)
{
sock = s;
}
int UDP::send(char message[], endpoint ep)
{
boost::asio::ip::udp::endpoint sender_ep;
Package data;
bzero(&data,sizeof (data));
PackageHead pack_info;
bzero(&pack_info,sizeof (pack_info));
unsigned int send_index = 0;
unsigned int receive_index = 0;
int returnlen = 0;
try {
int len = sizeof(message);
if( len > MAXLENGTH) //长度大于512,分包发送
{
int readed = 0;
int count = sizeof(message) / MAXLENGTH;
while(len){
memcpy(data.buff,message + readed,MAXLENGTH);
readed += MAXLENGTH;
len -= MAXLENGTH;
if(send_index == receive_index){
++send_index;
data.head.index = send_index;
if(count == 0)
data.head.len = sizeof (message) - readed;
data.head.len = MAXLENGTH;
--count;
data.head.crc32val = crc32(crc,(unsigned char *)data.buff,sizeof(data));
returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),ep);
sock->receive_from(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
receive_index = pack_info.index;
if(pack_info.errorFlag == 1)
{
pack_info.errorFlag = 0;
returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),ep);
}
}
else {
//index不同 重新发送
returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),sender_ep);
sock->receive_from(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
receive_index = pack_info.index;
}
}
}
else { //只需要一个包
// std::cout << "leave" << std::endl;
memcpy(data.buff,message,sizeof (message));
if(send_index == receive_index){
++send_index;
data.head.index = send_index;
data.head.len = sizeof (message);
data.head.crc32val = crc32(crc,(unsigned char *)data.buff,sizeof(data));
returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),ep);
sock->receive_from(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
std::cout << "leave" << std::endl;
receive_index = pack_info.index;
if(pack_info.errorFlag == 1)
{
pack_info.errorFlag = 0;
returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),ep);
}
}
else {
//index不同 重新发送
returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),sender_ep);
sock->receive_from(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
receive_index = pack_info.index;
}
}
} catch (boost::system::system_error e) {
std::cerr << e.what() << std::endl;
}
return returnlen;
}
std::string UDP::receive()
{
Package data;
bzero(&data,sizeof (data));
PackageHead pack_info; //返回给客户端包正确的消息
bzero(&pack_info,sizeof (pack_info));
unsigned int crc32value;
long int id = 1; //包序列号
char buffer[512];
bzero(buffer,sizeof (buffer)); //消息缓存
boost::asio::ip::udp::endpoint sender_ep;
//检测数据的完整
size_t len = sock->receive_from(boost::asio::buffer(reinterpret_cast(&data), sizeof(data)),sender_ep);
if(len < 0)
std::cout << "Receive Message From Client failed.\n";
else {
crc32value = crc32(crc,(unsigned char *)data.buff,sizeof(data)); //生成校验码
if(data.head.index == id)
{
if(data.head.crc32val == crc32value)
{
pack_info.index = data.head.index;
pack_info.len = len;
++id;
sock->send_to(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
memcpy(buffer,data.buff,sizeof (data.buff));
}
else {
//错误包,重发
pack_info.index = data.head.index;
pack_info.len = len;
pack_info.errorFlag = 1;
sock->send_to(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
}
}
else if (data.head.index < 0) {//重发包
pack_info.index = data.head.index;
pack_info.len = len;
pack_info.errorFlag = 0;
sock->send_to(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
}
else {
id = 1;
}
}
return buffer;
}
void UDP::receiveFile(FILE *fp)
{
std::cout << "=====Receive File Context=====" << std::endl;
int len = 0;
boost::asio::ip::udp::endpoint sender_ep;
unsigned int crc32tmp;
long int id = 1;
while(1)
{
PackageHead head; //定义确认包变量
Package data;
len = sock->receive_from(boost::asio::buffer(reinterpret_cast(&data), sizeof(data)),sender_ep);
if(len > 0)
{
crc32tmp = crc32(crc,(unsigned char *)data.buff,sizeof(data));
if(data.head.index == id)
{
if(data.head.crc32val == crc32tmp)
{
head.index = data.head.index;
head.len = len;
++id;
sock->send_to(boost::asio::buffer((char *)&head,sizeof(head)),sender_ep);
fwrite(data.buff,sizeof (char),data.head.len,fp);
}
else {
//错误包,重发
head.index = data.head.index;
head.len = len;
head.errorFlag = 1;
sock->send_to(boost::asio::buffer((char *)&head,sizeof(head)),sender_ep);
}
}
else if(data.head.index < id){ //重发包
head.index = data.head.index;
head.len = len;
head.errorFlag = 0;
sock->send_to(boost::asio::buffer((char *)&head,sizeof(head)),sender_ep);
}
else {
break;
}
}
else {
std::cout << "accept " << std::endl;
break;
}
}
fclose(fp);
std::cout << "Transfer successful." << std::endl;
}
long UDP::sendFile(FILE *fp,endpoint ep)
{
boost::asio::ip::udp::endpoint sender_ep;
//发送文件内容
long int send_id = 0;
long int receive_id = 0;
int len = 0; //记录数据长度
Package data;
long int total_bytes_read = 0;
while(true)
{
PackageHead head;
Package data;
bzero((char *)&data,sizeof(data));
if(receive_id == send_id)
{
++send_id;
len = fread(data.buff,sizeof(char),BUFFERSIZE,fp);
total_bytes_read += len;
if(len > 0)
{
data.head.index = send_id;
data.head.len = len;
data.head.crc32val = crc32(crc,(unsigned char *)data.buff,sizeof(data));
// std::cout<< "len " << len << std::endl;
// std::cout << "crc32: " << data.head.crc32val << std::endl;
sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),ep);
sock->receive_from(boost::asio::buffer((char *)&head,sizeof(head)),sender_ep);
receive_id = head.index;
// std::cout << "receive: " << head.index << std::endl;
if(head.errorFlag == 1)
{
head.errorFlag = 0;
sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),sender_ep);
}
}
else {
break;
}
}
else{
//index不同 重新发送
sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),sender_ep);
sock->receive_from(boost::asio::buffer((char *)&head,sizeof(head)),sender_ep);
receive_id = head.index;
}
}
bzero((char *)&data,sizeof(data));
sock->send_to(boost::asio::buffer((char *)&data,0),sender_ep);
return total_bytes_read;
}