这里对UDP进行了封装,封装出了一个UDPSender、一个UDPReceiver。
这里为什么要封装呢?
主要是想简明释义,一个类就一个方法,就做一件事,就一个接口,想用就用没有额外的复旦,构造函数强制要求需要的信息。能创建就能试用。
上面就是封装的理由和动机。
介绍:
UDPSender和UDPReceiver被封装在一个DLL中。因为发送和接收都是针对UDP的,而且就这么两个类,一个DLL比较合适,难道一个类也要单独放在一个DLL里面?真是的,小题大做。
双方由于不需要建立连接的过程,所以一个就连续发送,一个连续接收。
由于接收不过来就会丢包,所以发送速度是接收速度的1/2来缓解接收压力。
(其中一次测试,发送10001个,接收到了9860个,之所以丢包就是因为sender和receiver每次动作sleep的时间一样短,改成sender sleep(2time),receiver sleep(1time)就不丢数据了。)
test_UDPSender_main.cpp
#ifndef UDP_H
#include "UDP.h"
#endif
#include <string>
using namespace std;
#include "ace/OS.h"
#include "ace/Message_Block.h"
#include "ace/Service_Config.h"
#include "ace/Reactor.h"
int ACE_TMAIN (int argc, ACE_TCHAR *argv[])
{
if (ACE_Service_Config::open(argc,argv,
ACE_DEFAULT_LOGGER_KEY,1,0,1) < 0)
{
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p/n"), ACE_TEXT("Service Config open")), -1);
}
ACE_Message_Block* mb = new ACE_Message_Block(5000);
string str("carea");
for (int i=0;i<1000;++i)
{
mb->copy(str.c_str(),str.size());
}
int i = 0;
while (true)
{
//这里对象应该在循环外部创建以提高效率,而不用每次都创建临时对象发送,
//之所以放到这里是看看临时对象在释放会不会正常释放资源,经过测试是可以的
ACE_INET_Addr remote_addr("localhost:1032");
UDPSender udp_sender(1048);
int length = udp_sender.send_udp(mb->rd_ptr(),mb->length(),remote_addr);
if (length>0)
{
ACE_DEBUG((LM_DEBUG,"OK,send[%d] successed\n",
++i));
ACE_OS::sleep(ACE_Time_Value(0,20000));
if (i>1000)
{
break;
}
}
else
{
ACE_DEBUG((LM_ERROR,"NO,send failed\n"));
break;
}
}
mb->release();
ACE_Reactor::instance()->run_reactor_event_loop();
return 0;
};
发送端发完了全部的包,每个发送对象发送完毕之后在析构的时候close socket
test_UDPReceiver_main.cpp
#ifndef UDP_H
#include "UDP.h"
#endif
#include "ace/OS.h"
#include "ace/Reactor.h"
#include "ace/Service_Config.h"
int ACE_TMAIN (int argc, ACE_TCHAR *argv[])
{
if (ACE_Service_Config::open(argc,argv,
ACE_DEFAULT_LOGGER_KEY,1,0,1) < 0)
{
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p/n"), ACE_TEXT("Service Config open")), -1);
}
char arr[10001]={0};
UDPReceiver udp_receiver(1032);
ACE_INET_Addr remote_addr("localhost:1048");
int i = 0;
while (true)
{
int length = udp_receiver.receive_udp(arr,sizeof(arr),remote_addr);
if (length>0)
{
ACE_DEBUG((LM_DEBUG,"OK,receive th %ds successed\n",
++i));
ACE_OS::sleep(ACE_Time_Value(0,10000));
}
else
{
ACE_DEBUG((LM_ERROR,"NO,receive failed\n"));
break;
}
}
ACE_Reactor::instance()->run_reactor_event_loop();
return 0;
};
接收端收到了全部的包
封装DLL所需的文件
头文件SCP_Export.h
#ifndef SCP_EXPORT_H
#define SCP_EXPORT_H
#ifdef WIN32 //for windows
#ifdef SCP_EXPORTS //for windows generate dll,you have to define SCP_EXPORTS in your preprocessor
#define SCP_Export __declspec(dllexport)
#else
#define SCP_Export //for windows as source file
#endif
#else //for Linux
#ifdef SCP_EXPORTS //for Linux as source file
#define SCP_Export
#else
#define SCP_Export //for Linux generate dll
#endif
#endif
#endif
头文件UDP.h
#ifndef UDP_H
#define UDP_H
#include "ace/INET_Addr.h"
#include "ace/SOCK_Dgram.h"
#include "ace/Message_Block.h"
#include "ace/Log_Msg.h"
#include "ace/SOCK_Dgram_Bcast.h"
#include <string>
using std::string;
#ifndef SCP_EXPORT_H
#include "SCP_Export.h"
#endif
class SCP_Export UDP
{
public:
explicit UDP(u_short local_port);
~UDP();
protected:
ACE_INET_Addr local_port_addr_;
ACE_SOCK_Dgram peer_; //本地地址藏匿于此,发送的时候除了知道目的地址,也要携带本地地址的(因为UDP没有连接这一说)
};
class SCP_Export UDPSender : public UDP
{
public:
UDPSender(u_short port_number);
int send_udp (const void* message,const int length,const ACE_INET_Addr& remote_addr);
};
class SCP_Export UDPReceiver : public UDP
{
public:
//在指定端口接收UDP报文
explicit UDPReceiver(u_short port_number);
//返回receive_length == -1 表示未接收到,
//接收内容放到mb中,
//对方地址在remote_addr
int receive_udp(char* buffer,const int buffer_length,ACE_INET_Addr& remote_addr);
};
#endif
源文件UDP.cpp
#include "UDP.h"
UDP::UDP(u_short local_port)
:local_port_addr_(local_port),peer_(local_port_addr_)
{
ACE_DEBUG((LM_INFO,"UDP(%d)\n",local_port));
}
UDP::~UDP()
{
ACE_DEBUG((LM_INFO,"~UDP() socket closed.\n"));
this->peer_.close();
}
UDPSender::UDPSender(u_short port_number)
:UDP(port_number)
{
}
int UDPSender::send_udp (const void* message,const int length,const ACE_INET_Addr& remote_addr)
{
int send_bytes = this->peer_.send(message,length,remote_addr);
if (send_bytes == -1)
{
ACE_ERROR((LM_ERROR,
ACE_TEXT("(%P|%t) UDP send to %s %p\n"),
remote_addr.get_host_addr(),
ACE_TEXT ("failed")));
}
return send_bytes;
}
UDPReceiver::UDPReceiver(u_short port_number)
:UDP(port_number)
{
ACE_DEBUG((LM_INFO,"UDPReceiver(%d)\n",port_number));
}
int UDPReceiver::receive_udp(char* buffer,const int buffer_length,ACE_INET_Addr& remote_addr)
{
int receive_length = peer_.recv(buffer,buffer_length,remote_addr); //接收消息,获取远程地址信息
if (receive_length != -1)
{
string str(buffer,buffer_length);
ACE_DEBUG((LM_DEBUG,"UDPReceiver receive length[%d]\n",
receive_length));
}
else
{
ACE_DEBUG((LM_ERROR,"UDPReceiver::receive_udp failed\n"));
}
return receive_length;
}