前言:
前一篇文章minidlna源码初探(二)—— SSDP设备发现的大致流程介绍了SSDP设备发现的大致流程。本文将根据这一流程使用ACE库大致实现该流程。在VLC中模拟出一个伪服务端(设备),为了方便,我们省略了一些验证的内容,对一些XML消息也采取写死的方式。
正文:
首先,我们需要一个消息循环,如下:
//创建组播SOCKET
ACE_SOCK_Dgram_Mcast udp;
ACE_INET_Addr mcast_inet("239.255.255.250:1900");
udp.join(mcast_inet);
udp.set_option(IP_MULTICAST_TTL, MAX_MULTICAST_IP_TTL);
//创建单址SOCKET
ACE_HANDLE peer_handle = GetPeerListenSocket(8200);
thread_pool thrd_pool; //新建线程池
thrd_pool.run(); //启动线程池
while(1)
{
if ((GetCurrentSecond() - time_record) > 20)
{
handle_alive(udp);
time_record = GetCurrentSecond(); //定时组播ssdp:alive消息
}
active_handle_set.set_bit(udp_handle);
active_handle_set.set_bit(peer_handle);
width = (int)active_handle_set.max_set() + 1;
if (ACE::select(width , &active_handle_set , 0 , 0 , &atv) < 1) //监听组播和单址是否有请求
{
continue;
}
if (active_handle_set.num_set() <= 0)
{
continue;
}
ACE_Handle_Set_Iterator iterator(active_handle_set);
ACE_HANDLE handle = iterator();
for (; handle != ACE_INVALID_HANDLE; handle = iterator())
{
if (handle == udp_handle) //处理组播请求
{
{
boost::mutex::scoped_lock lock(transform_mutex);
res = udp.recv(buf , 512 , remote_inet_addr);
if(res <= 0) continue;
}
std::map<ACE_HANDLE , std::string> m;
m.insert(std::pair<ACE_HANDLE , std::string>(udp_handle , std::string(buf)));
thrd_pool.push_task(m); //向线程池push新的消息
}
if (handle == peer_handle) //处理单地请求
{
std::map<ACE_HANDLE , std::string> m;
m.insert(std::pair<ACE_HANDLE , std::string>(peer_handle , std::string("HANDLE_PEER_ACCEPTOR")));
thrd_pool.push_task(m); //向线程池push新的消息
}
}
}
消息循环定时组播ssdp:alive消息,并获取组播或者单址传递来的消息。然后将SOCKET handle连同消息存入一个std::map<ACE_HANDLE , std::string>容器,随后将这个map压入线程池中的队列。线程池代码如下:
class thread_pool : public boost::noncopyable
{
private:
boost::thread_group thrds;
boost::mutex io_mutex;
std::map<std::string , std::string>::iterator iter;
static bool finish;
int thr