天天看點

關于socket多點傳播和ssdp(二)1、說明2、show me the code,以下用boost庫來做多點傳播的接收和發送3、有關于wireshark 抓包4 、 接下來使用http去接收和發送資料5、總結

關于socket多點傳播和ssdp(一)

1、說明

在制作的過程中,實際上ssdp發現協定特别簡單,隻是加入多點傳播後,發送搜尋的字元串,然後再在單點傳播上接收,如果是發送,則要發送到多點傳播位址,而且,發送的字元串不能出錯,這裡說明作者的一個錯誤,開始時,“MAN: “ssdp:discover”\r\n”,一直寫成了"MAN: ssdp:discover\r\n",是以在單點傳播上沒有收到資料,值得注意!

2、show me the code,以下用boost庫來做多點傳播的接收和發送

socket.bind(

udp::endpoint(boost::asio::ip::address_v4::any(),

receiver ? port ));

以上這句話比較重要,在使用發送的時候,使用多點傳播端口,接收的時候,使用本地的一個端口,切記!

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
// 3rd party includes.
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <string>


static const char msearchmsgfmt[] = "M-SEARCH * HTTP/1.1\r\n"
"Connection: close"
"HOST: 239.255.255.250:1900\r\n"
"ST: %s\r\n"
"MAN: \"ssdp:discover\"\r\n"
"USER-AGENT: qbupnp 1.0"
"MX: 3\r\n\r\n";



void read(boost::asio::ip::udp::socket& socket)
    {
        boost::asio::ip::udp::endpoint sender;
        std::vector<char> buffer;
        std::size_t bytes_readable = 0;
        for (;;)
        {
            // Poll until data is available.
            while (!bytes_readable)
            {
                // Issue command to socket to get number of bytes readable.
                boost::asio::socket_base::bytes_readable num_of_bytes_readable(true);
                socket.io_control(num_of_bytes_readable);

                // Get the value from the command.
                bytes_readable = num_of_bytes_readable.get();

                // If there is no data available, then sleep.
                if (!bytes_readable)
                {
                    boost::this_thread::sleep(boost::posix_time::seconds(1));
                }
            }

            // Resize the buffer to store all available data.
            buffer.resize(bytes_readable);

            // Read available data.
            socket.receive_from(
                boost::asio::buffer(buffer, bytes_readable),
                sender);

            // Extract data from the buffer.
            std::string message(buffer.begin(), buffer.end());

            // Output data.
            std::cout << "Received message: ";
            std::cout << message << std::endl;
        }
    }

void write(boost::asio::ip::udp::socket& socket,
	boost::asio::ip::udp::endpoint& destination)
{
	std::string message;

	char buffer[256];
	sprintf(buffer, msearchmsgfmt, "upnp:rootdevice");
	/*socket.async_send_to(
		boost::asio::buffer(buffer, strlen(buffer)), endpoint_,
		boost::bind(handle_send_to, this,
			boost::asio::placeholders::error));*/

	for (unsigned int i = 0; i < 3; ++i)
	{
		//std::ostringstream stream;
		//stream << i;
		//message = stream.str();
		socket.send_to(boost::asio::buffer(msearchmsgfmt, strlen(msearchmsgfmt)), destination);
		std::cout << "Sent message: " << message << std::endl;
	}
}


int main(int argc, char* argv[])
{
    // Extract command-line arguments.
    bool receiver = false;// std::string(argv[1]) == "receive";
    boost::asio::ip::address address =
        boost::asio::ip::address::from_string("239.255.255.250");
    unsigned short port = 1900;  

    // Create socket.
    using boost::asio::ip::udp;
    boost::asio::io_service service;
    udp::socket socket(service);
    socket.open(boost::asio::ip::udp::v4());

    // Allow other processes to reuse the address, permitting other processes on
    // the same machine to use the multicast address.
    socket.set_option(udp::socket::reuse_address(true));

    
    socket.set_option(boost::asio::ip::multicast::enable_loopback(true));
    socket.bind(
        udp::endpoint(boost::asio::ip::address_v4::any(),
            receiver ? port /* same as multicast port */
            : 6200 /* any */));
    udp::endpoint destination(address, port);

    // Join group.
    namespace ip = boost::asio::ip;
    socket.set_option(ip::multicast::join_group(address));

    // Start read or write loops based on command line options.
    if (receiver) 
    	read(socket);
    else
        write(socket, destination);
    return 0;
}

           

3、有關于wireshark 抓包

注意使用port 1900 的包在區域網路裡面應該是有很多的,包含網關的,chrome 發送的ssdp,等等,讀者可以适當自己過濾加上not host 192.168.0.1 諸如此類的網關過濾

關于socket多點傳播和ssdp(二)1、說明2、show me the code,以下用boost庫來做多點傳播的接收和發送3、有關于wireshark 抓包4 、 接下來使用http去接收和發送資料5、總結

4 、 接下來使用http去接收和發送資料

建議

1 使用boost asio庫直接接收發送,甚至直接使用asio

2 使用httplib接收發送

3 使用nlohmann 解析json

4 xml 庫可以使用ixml,或者直接手動解析:

如何手動解析xml

以上為什麼推薦使用httplib,和 nlohmann,這兩個隻要加入頭檔案即可,不用編譯。為什麼使用asio,可以直接使用頭檔案,簡化加載庫,以及asio封裝得非常友善。

5、總結

使用以上工具和方法,作者做出了一個ssdp搜尋和控制工具,仿照libpnp來做的,研讀了很多代碼,讀者可以沿着作者走過的路走一遍。

關于socket多點傳播和ssdp(二)1、說明2、show me the code,以下用boost庫來做多點傳播的接收和發送3、有關于wireshark 抓包4 、 接下來使用http去接收和發送資料5、總結

列印控制點

關于socket多點傳播和ssdp(二)1、說明2、show me the code,以下用boost庫來做多點傳播的接收和發送3、有關于wireshark 抓包4 、 接下來使用http去接收和發送資料5、總結

投屏服務用戶端

關于socket多點傳播和ssdp(二)1、說明2、show me the code,以下用boost庫來做多點傳播的接收和發送3、有關于wireshark 抓包4 、 接下來使用http去接收和發送資料5、總結

總之,dlna和libupnp協定并不難懂,其實就是一系列協定的組合,甚至大量使用了http協定,在檔案點播和直播方面,可以使用rtsp協定和http協定等等,隻要深度研究這些基礎協定,就可以做出相應的産品。

以上都是作者的事件經驗,讀者需要交流,可以使用[email protected],或者微信聯系。

繼續閱讀