2013-04-13 90 views
0

您好,我正在嘗試使用Boost C++ UDP客戶端服務器。Boost C++ UDP示例無法通過互聯網傳輸

我拿了ASIO附帶的一個例子,並修改了一下。

它在本地網絡上工作得很好,但是當我將服務器託管到我們的服務器並且端口正確轉發時,它不起作用。

我運行UDP服務器,並嘗試通過互聯網與家中的客戶端進行傳輸,但沒有任何數據包到達服務器。我確信這些端口是正確轉發的,並且防火牆不會阻礙。

就UDP通信而言,本地網絡和互聯網是否有區別?

以下是客戶端和服務器的代碼:

---- ----客戶

#include <cstdlib> 
#include <cstring> 
#include <iostream> 
#include <boost/asio.hpp> 

using boost::asio::ip::udp; 
enum { max_length = 1024 }; 

int main(int argc, char* argv[]) 
{ 
char request[max_length]; 
try 
{ 

    boost::asio::io_service io_service; 

    udp::socket s(io_service, udp::endpoint(udp::v4(), 0)); 

    udp::resolver resolver(io_service); 
    udp::resolver::query query(udp::v4(), "MyPublicIp", "3002"); 
    udp::resolver::iterator iterator = resolver.resolve(query); 

    using namespace std; // For strlen. 
    std::cout << "Write to me: "; 
    while(1) 
    { 
     std::cin.getline(request, max_length); 
     size_t request_length = strlen(request); 
     s.send_to(boost::asio::buffer(request, request_length), *iterator); 

     char reply[max_length]; 
     udp::endpoint sender_endpoint; 
     size_t reply_length = s.receive_from(boost::asio::buffer(reply, max_length), sender_endpoint); 
     std::cout << Say:"; 
     std::cout.write(reply, reply_length); 
     std::cout << "\n"; 
     std::cout << Say What?" ; 
    } 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    } 
    std::cin.getline(request, max_length); 
    return 0; 
} 

------服務器---------- -

#include <boost/chrono.hpp> 
#include <cstdlib> 
#include <iostream> 
#include <boost/bind.hpp> 
#include <boost/asio.hpp> 
#include <boost\thread\thread.hpp> 
#include <ctime> 
using boost::asio::ip::udp; 

class server 
{ 
public: 
    server(boost::asio::io_service& io_service, short port) 
    : io_service_(io_service), 
     socket_(io_service, udp::endpoint(boost::asio::ip::address_v4::any(), port)) 
    { 
     std::fill(data_, data_ + max_length, 0); 
    socket_.async_receive_from(
     boost::asio::buffer(data_, max_length), sender_endpoint_, 
     boost::bind(&server::handle_receive_from, this, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 
    } 

    void handle_receive_from(const boost::system::error_code& error, 
     size_t bytes_recvd) 
    { 
    if (!error && bytes_recvd > 0) 
    { 
     td::cout << "Connection from: " << sender_endpoint_.address().to_string() << " " << sender_endpoint_.port() << std::endl; 

     socket_.async_send_to(
      boost::asio::buffer(data_, strlen(data_)), sender_endpoint_, 
      boost::bind(&server::handle_send_to, this, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 
    } 
    else 
    { 
     socket_.async_receive_from(
      boost::asio::buffer(data_, max_length), sender_endpoint_, 
      boost::bind(&server::handle_receive_from, this, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 
    } 
    } 

    void handle_send_to(const boost::system::error_code& /*error*/, 
     size_t /*bytes_sent*/) 
    { 

     std::fill(data_, data_ + max_length, 0); 
    socket_.async_receive_from(
     boost::asio::buffer(data_, max_length), sender_endpoint_, 
     boost::bind(&server::handle_receive_from, this, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 

    } 

private: 
    boost::asio::io_service& io_service_; 
    udp::socket socket_; 
    udp::endpoint sender_endpoint_; 
    enum { max_length = 300 }; 
    char data_[max_length]; 
}; 

int main(int argc, char* argv[]) 
{ 
    try 
    { 
    std::cout << "Starting server" << std::endl; 

    boost::asio::io_service io_service; 
    short port = 3002; 
    using namespace std; 
    server s(io_service, port); 
    std::cout << "Server started. Listening on port:" <<port << std::endl; 
    io_service.run(); 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    } 
    return 0; 
} 
+0

嘗試telnet服務器。 telnet MyPublicIp 3002.可能有很多問題。您的電腦可能會阻止通信。您的ISP可能會阻止它。 – selalerer

+2

最可能的解釋是端口轉發實際上沒有正確設置,或者您和服務器之間的NAT層數多於您認爲的數量。 –

+0

嗯,我不能telnet,因爲我使用UDP。 有什麼方法可以告訴數據包被丟棄的是什麼點? – Cyril

回答

3

從傳輸層的角度來看,本地網絡與互聯網之間的UDP沒有區別。然而,有各種因素可以發揮作用:

  • UDP缺乏可靠性。大多數情況下,執行單個寫入並同步阻止等待響應將在局域網上產生很好的結果,並且噪聲最小。但是,修改客戶端可能會值得在通過互聯網時丟失數據。如果應用程序需要高度的可靠性,那麼請考慮使用不同的傳輸層協議,如TCP。
  • 如果服務器和客戶端位於同一網絡上,但客戶端正試圖通過網絡的外部IP連接到服務器,則驗證該網關是否支持環回指向外部IP的內部流量。
  • 執行跟蹤路由以驗證IP數據包的time to live字段是否足夠用於客戶端和服務器之間的路由。
  • 驗證客戶端和服務器之間的路由設備是否支持正確的NAT。 RFC 4787詳細描述了UDP和NAT要求。如果服務器實際上不可公開訪問,則可能需要UDP Hole Punching

在大多數情況下,如果客戶端和服務器在LAN上工作,那麼這通常是一個網絡問題。使用基本工具(如netcat)和使用可靠的基於連接的協議(如TCP)來調試網絡可能是值得的。一旦觀察到連接,然後切換到使用UDP客戶端和服務器。