2010-01-11 38 views
22

Tôi có một thử nghiệm hiệu suất máy chủ/khách hàng rất đơn giản bằng cách sử dụng boost :: asio trên Windows và có vẻ như nó hoạt động kém. Tôi hy vọng rằng tôi chỉ sử dụng thư viện không chính xác và sẽ đánh giá cao bất kỳ lời khuyên nào.Hiệu suất tăng thấp.ASIO

Tôi có một lớp phiên viết độ dài tin nhắn và sau đó viết một tin nhắn, và sau đó chờ đợi để đọc một chiều dài tin nhắn và sau đó đọc một tin nhắn, và tiếp tục làm điều này hơn và hơn nữa không ngừng nghỉ. Khi tôi chạy nó cục bộ trên máy tính của riêng tôi, tôi nhận được hiệu suất cực nhanh, tuy nhiên; khi tôi chạy một máy chủ trên một máy tính và một máy khách trên một máy tính khác, ngay cả trên cùng một mạng, hiệu năng sẽ chậm lại, mất tới 1 giây để hoạt động đọc/ghi xảy ra.

Các máy chủ mã nguồn tập tin là như sau:

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

using namespace boost; 
using namespace boost::asio; 
using namespace boost::asio::ip; 
using namespace std; 

class Session { 
    public: 

    Session(io_service& ioService) 
     : m_socket(ioService) {} 

    tcp::socket& GetSocket() { 
     return m_socket; 
    } 

    void StartRead() { 
     m_messageSizeIterator = reinterpret_cast<char*>(&m_messageSize); 
     async_read(m_socket, buffer(m_messageSizeIterator, sizeof(m_messageSize)), 
     bind(&Session::HandleSizeRead, this, placeholders::error, 
     placeholders::bytes_transferred)); 
    } 

    void StartWrite(const char* message, int messageSize) { 
     m_messageSize = messageSize; 
     m_message = new char[m_messageSize]; 
     memcpy(m_message, message, m_messageSize); 
     async_write(m_socket, buffer(&m_messageSize, sizeof(int)), 
     bind(&Session::HandleSizeWritten, this, placeholders::error)); 
    } 

    void HandleSizeRead(const system::error_code& error, 
     size_t bytes_transferred) { 
     if(!error) { 
     m_message = new char[m_messageSize]; 
     async_read(m_socket, buffer(m_message, m_messageSize), 
      bind(&Session::HandleMessageRead, this, placeholders::error, 
      placeholders::bytes_transferred)); 
     } else { 
     delete this; 
     } 
    } 

    void HandleMessageRead(const system::error_code& error, 
     size_t bytes_transferred) { 
     if(!error) { 
     cout << string(m_message, m_messageSize) << endl; 
     async_write(m_socket, buffer(&m_messageSize, sizeof(int)), 
      bind(&Session::HandleSizeWritten, this, placeholders::error)); 
     } else { 
     delete this; 
     } 
    } 

    void HandleSizeWritten(const system::error_code& error) { 
     if(!error) { 
     async_write(m_socket, buffer(m_message, m_messageSize), 
      bind(&Session::HandleMessageWritten, this, placeholders::error)); 
     } else { 
     delete this; 
     } 
    } 

    void HandleMessageWritten(const system::error_code& error) { 
     if(!error) { 
     delete m_message; 
     m_messageSizeIterator = reinterpret_cast<char*>(&m_messageSize); 
     async_read(m_socket, buffer(m_messageSizeIterator, 
      sizeof(m_messageSize)), bind(&Session::HandleSizeRead, this, 
      placeholders::error, placeholders::bytes_transferred)); 
     } else { 
     delete this; 
     } 
    } 

    private: 
    tcp::socket m_socket; 
    int m_messageSize; 
    char* m_messageSizeIterator; 
    char* m_message; 
}; 

class Server { 
    public: 

    Server(io_service& ioService, short port) 
     : m_ioService(ioService), 
      m_acceptor(ioService, tcp::endpoint(tcp::v4(), port)) { 
     Session* new_session = new Session(m_ioService); 
     m_acceptor.async_accept(new_session->GetSocket(), bind(&Server::HandleAccept, 
     this, new_session,asio::placeholders::error)); 
    } 

    void HandleAccept(Session* new_session, const system::error_code& error) { 
     if(!error) { 
     new_session->StartRead(); 
     new_session = new Session(m_ioService); 
     m_acceptor.async_accept(new_session->GetSocket(), bind(
      &Server::HandleAccept, this, new_session, placeholders::error)); 
     } else { 
     delete new_session; 
     } 
    } 

    private: 
    io_service& m_ioService; 
    tcp::acceptor m_acceptor; 
}; 

int main(int argc, char* argv[]) { 
    try { 
    if(argc != 2) { 
     cerr << "Usage: server <port>\n"; 
     return 1; 
    } 
    io_service io_service; 
    Server s(io_service, atoi(argv[1])); 
    io_service.run(); 
    } catch(std::exception& e) { 
    cerr << "Exception: " << e.what() << "\n"; 
    } 
    return 0; 
} 

Và mã khách hàng như sau:

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

using namespace boost; 
using namespace boost::asio; 
using namespace boost::asio::ip; 
using namespace std; 

class Session { 
    public: 

    Session(io_service& ioService) 
     : m_socket(ioService) {} 

    tcp::socket& GetSocket() { 
     return m_socket; 
    } 

    void StartRead() { 
     m_messageSizeIterator = reinterpret_cast<char*>(&m_messageSize); 
     async_read(m_socket, buffer(m_messageSizeIterator, sizeof(m_messageSize)), 
     bind(&Session::HandleSizeRead, this, placeholders::error, 
     placeholders::bytes_transferred)); 
    } 

    void StartWrite(const char* message, int messageSize) { 
     m_messageSize = messageSize; 
     m_message = new char[m_messageSize]; 
     memcpy(m_message, message, m_messageSize); 
     async_write(m_socket, buffer(&m_messageSize, sizeof(int)), 
     bind(&Session::HandleSizeWritten, this, placeholders::error)); 
    } 

    void HandleSizeRead(const system::error_code& error, 
     size_t bytes_transferred) { 
     if(!error) { 
     m_message = new char[m_messageSize]; 
     async_read(m_socket, buffer(m_message, m_messageSize), 
      bind(&Session::HandleMessageRead, this, placeholders::error, 
      placeholders::bytes_transferred)); 
     } else { 
     delete this; 
     } 
    } 

    void HandleMessageRead(const system::error_code& error, 
     size_t bytes_transferred) { 
     if(!error) { 
     cout << string(m_message, m_messageSize) << endl; 
     async_write(m_socket, buffer(&m_messageSize, sizeof(int)), 
      bind(&Session::HandleSizeWritten, this, placeholders::error)); 
     } else { 
     delete this; 
     } 
    } 

    void HandleSizeWritten(const system::error_code& error) { 
     if(!error) { 
     async_write(m_socket, buffer(m_message, m_messageSize), 
      bind(&Session::HandleMessageWritten, this, placeholders::error)); 
     } else { 
     delete this; 
     } 
    } 

    void HandleMessageWritten(const system::error_code& error) { 
     if(!error) { 
     delete m_message; 
     m_messageSizeIterator = reinterpret_cast<char*>(&m_messageSize); 
     async_read(m_socket, buffer(m_messageSizeIterator, 
      sizeof(m_messageSize)), bind(&Session::HandleSizeRead, this, 
      placeholders::error, placeholders::bytes_transferred)); 
     } else { 
     delete this; 
     } 
    } 

    private: 
    tcp::socket m_socket; 
    int m_messageSize; 
    char* m_messageSizeIterator; 
    char* m_message; 
}; 

int main(int argc, char* argv[]) { 
    try { 
    if(argc != 3) { 
     cerr << "Usage: client <host> <port>\n"; 
     return 1; 
    } 
    io_service io_service; 
    tcp::resolver resolver(io_service); 
    tcp::resolver::query query(tcp::v4(), argv[1], argv[2]); 
    tcp::resolver::iterator iterator = resolver.resolve(query); 
    Session session(io_service); 
    tcp::socket& s = session.GetSocket(); 
    s.connect(*iterator); 
    cout << "Enter message: "; 
    const int MAX_LENGTH = 1024; 
    char request[MAX_LENGTH]; 
    cin.getline(request, MAX_LENGTH); 
    int requestLength = strlen(request); 
    session.StartWrite(request, requestLength); 
    io_service.run(); 
    } catch (std::exception& e) { 
    cerr << "Exception: " << e.what() << "\n"; 
    } 
    return 0; 
} 

Bất kỳ trợ giúp sẽ được đánh giá, cảm ơn.


Vì mục đích của tôi, gửi các thư thực sự nhỏ và muốn trả lời thời gian thực ảo, tắt thuật toán của Nagle hóa ra là nguyên nhân của hiệu suất kém.

+0

Bạn đã loại trừ khả năng một số thứ mà bộ định tuyến của bạn có thể đang gây ra sự cố? Việc sử dụng CPU như thế nào trên mỗi máy? – bobber205

+0

Mức sử dụng CPU là 0 trên cả hai máy. Đối với router là vấn đề, tôi đã viết một chương trình tương tự mà không cần sử dụng ASIO và nó hoạt động rất nhanh. – Kranar

+3

Bắt đầu bằng cách kiểm tra liên kết của bạn bằng iperf. Sau đó, thiết bị toàn bộ quá trình - Ổ cắm có được tạo ra không? Liên kết có thành công không? Giải quyết có hiệu quả không? Kết nối với máy chủ có hoạt động không? Người gửi đầu tiên có làm việc không? Người đầu tiên nhận được công việc? Có bất kỳ cuộc gọi API mạng nào trả lại bất kỳ lỗi nào không? Có phải mất nhiều thời gian hơn dự kiến ​​không? Nhìn vào lưu lượng mạng. Có tường lửa trên máy chủ không? Thuật toán Nagle có được bật không? Máy chủ có mất nhiều thời gian để phản hồi không? Có sự chậm trễ nào bạn không mong đợi trong mã không phải mạng trong máy khách không? – Permaquid

Trả lời

36

Bạn phải tắt Nagle algorithm. Gọi:

m_socket.set_option(tcp::no_delay(true)); 

Nếu thích hợp cho mã của bạn.

+0

+1 cho đề xuất và liên kết trong nagle trên wiki. Tuy nhiên - có lẽ đã muốn thấy một cảnh báo rằng việc biến Nagle có lẽ sẽ thấp hơn thông lượng tổng thể. – quixver

+2

@quixver Không có vấn đề gì sẽ dẫn đến nhiều gói hơn trên mạng nếu bạn đang gửi byte với khoảng cách nhỏ giữa chúng. Một bộ đếm thời gian (tức là Nagle) để kết hợp sẽ dẫn đến các gói dữ liệu ít hơn và do đó cải thiện thông lượng mạng tổng thể. Điều này đúng với lưu lượng bàn phím tương tác (ví dụ: telnet, ssh) và là một phần lớn của lưu lượng truy cập Ethernet hai mươi năm trước. Đối với giao tiếp chương trình-chương trình, Nagle dẫn đến thông lượng tổng thể thấp hơn (như trường hợp trong câu hỏi ban đầu) hơn là thông lượng cao hơn. Xem, ví dụ, toàn bộ tin nhắn đã được chuyển đến async_write(), và do đó không cần phải đợi để gửi. – janm

6

Vì mục đích của tôi, gửi các thư thực sự nhỏ và muốn trả lời thời gian thực ảo, việc tắt thuật toán của Nagle hóa ra là nguyên nhân của hiệu suất kém.