2011-11-12 2 views
1

나는 C++을 배웠다. 이제 나는 나아가서 몇 가지 네트워크 프로그래밍을 배우고 싶다. 나는 multiplatform이기 때문에 boost :: asio를 사용하기로 결정했다. 나는이 간단한 프로그램을 작성 :boost :: asio 각 클라이언트에 대한 별도의 배열

클라이언트 :

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

using boost::asio::ip::tcp; 

enum { max_length = 1000000 }; 

int main(int argc, char* argv[]) 
{ 
    while(1) 
     { 

    try 
    { 
    if (argc != 3) 
    { 
     std::cerr << "Usage: blocking_tcp_echo_client <host> <port>\n"; 
     return 1; 
    } 

    boost::asio::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); 

    tcp::socket s(io_service); 
    s.connect(*iterator); 

    using namespace std; // For strlen. 

    std::cout << "Enter message: "; 
    char request[max_length]; 
    std::cin.getline(request, max_length); 
    if (request == "\n") 
     continue; 

    size_t request_length = strlen(request); 
    boost::asio::write(s, boost::asio::buffer(request, request_length)); 

    char reply[max_length]; 
    boost::system::error_code error; 
    size_t reply_length = s.read_some(boost::asio::buffer(reply), error); 

    if (error == boost::asio::error::eof) 
    break; // Connection closed cleanly by peer. 
    else if (error) 
    throw boost::system::system_error(error); // Some other error. 




    std::cout << "Reply is: "; 
    std::cout.write(reply, reply_length); 

    std::cout << "\n"; 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    exit(1); 
    } 
    } 

    return 0; 
} 

서버 :

#include <cstdlib> 
#include <iostream> 
#include <boost/bind.hpp> 
#include <boost/smart_ptr.hpp> 
#include <boost/asio.hpp> 
#include <boost/thread.hpp> 
#include <boost/regex.hpp> 
#include <boost/lexical_cast.hpp> 
#include <string> 

using boost::asio::ip::tcp; 
const int max_length = 1000000; 

std::string user_array[100]; 

typedef boost::shared_ptr<tcp::socket> socket_ptr; 

unsigned short analyze_user_request(std::string& user_request, short unsigned* ID, std::string* request_value) 
{ 
    // function returns: 
    // 0: if user request is incorrect 
    // 1: if user requests "PUT" operation 
    // 2: if user requests "GET" operation 
    // Furthermore, if request is correct, its value (i.e. ID number and/or string) is saved to short unsigned and string values passed by pointers. 

boost::regex exp("^[[:space:]]*(PUT|GET)[[:space:]]+([[:digit:]]{1,2})(?:[[:space:]]+(.*))?$"); 

    boost::smatch what; 
    if (regex_match(user_request, what, exp, boost::match_extra)) 
    { 
    short unsigned id_number = boost::lexical_cast<short unsigned>(what[2]); 

    if (what[1] == "PUT") 
     { 
     boost::regex exp1("^[a-zA-Z0-9]+$"); 
    std::string value = boost::lexical_cast<std::string>(what[3]); 
    if (value.length() > 4095) 
     return 0; 
    if (!regex_match(value, exp1)) 
     return 0; 
    else 
     { 
      *request_value = value; 
      *ID = id_number; 
     return 1; 
      } 
     } 

    if (what[1] == "GET") 
     { 
    *ID = id_number; 
     return 2; 
     } 

    } 

    if (!regex_match(user_request, what, exp, boost::match_extra)) 
    return 0; 
    } 


void session(socket_ptr sock) 
{ 
    try 
    { 
    for (;;) 
    { 
     char data[max_length]; 

     boost::system::error_code error; 
     size_t length = sock->read_some(boost::asio::buffer(data), error); 
     if (error == boost::asio::error::eof) 
     break; // Connection closed cleanly by peer. 
     else if (error) 
     throw boost::system::system_error(error); // Some other error. 
     // convert buffer data to string for further procession 
     std::string line(boost::asio::buffers_begin(boost::asio::buffer(data)), boost::asio::buffers_begin(boost::asio::buffer(data)) + length); 
     std::string reply; // will be "QK", "INVALID", or "OK <value>" 
      unsigned short vID; 

     unsigned short* ID = &vID; 
     std::string vrequest_value; 
     std::string* request_value = &vrequest_value; 

     unsigned short output = analyze_user_request(line, ID, request_value); 

     if (output == 1) 
    { 
    // PUT  
     reply = "OK"; 
     user_array[*ID] = *request_value; 
    } 

     else if (output == 2) 
     { 
     // GET 
     reply = user_array[*ID]; 
     if (reply == "") 
      reply = "EMPTY"; 

     } 

    else 
     reply = "INVALID"; 

      boost::system::error_code ignored_error; 
      size_t ans_len=reply.length(); 
     boost::asio::write(*sock, boost::asio::buffer(reply)); 
    } 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception in thread: " << e.what() << "\n"; 
    } 
} 

void server(boost::asio::io_service& io_service, short port) 
{ 
    tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port)); 
    for (;;) 
    { 
    socket_ptr sock(new tcp::socket(io_service)); 
    a.accept(*sock); 
    boost::thread t(boost::bind(session, sock)); 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    try 
    { 
    if (argc != 2) 
    { 
     std::cerr << "Usage: blocking_tcp_echo_server <port>\n"; 
     return 1; 
    } 

    boost::asio::io_service io_service; 

    using namespace std; // For atoi. 
    server(io_service, atoi(argv[1])); 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 

기본적으로, 사용자가 서버에 데이터를 저장 할 수있는 응용 프로그램입니다. ID 번호와 데이터 값이 뒤 따르는 PUT 명령을 사용하여 새 데이터를 삽입하고 GET 명령과 ID를 사용하여 데이터를 검색 할 수 있습니다. 사용자 요청은 analyze_user_request 함수에서 처리 된 후 어레이에 쓰거나 어레이에서 읽습니다. 문제는 이제 모든 클라이언트가 동일한 전역 arry를 사용하고 있다는 것입니다. 즉, 한 클라이언트가 특정 ID 아래에 무언가를 저장하면 다른 클라이언트는 모두 동일한 배열에 액세스하므로 읽을 수 있습니다. 배열을 다른 클라이언트와 어떻게 연관시킬 수 있을까요? 그리고 새로운 클라이언트가 연결될 때 새로운 배열을 생성 할 수 있습니까?

+2

어떻게 클래스의 클라이언트를 캡슐화 어떻습니까? – netcoder

답변

0

세션 데이터를 클래스로 캡슐화하고 각 연결에 대해 별도의 세션 객체를 만드는 것은 어떻습니까? 약은 다음과 같을 수 있습니다

세션 클래스 정의 :

class Session { 
public: 
// logic from your session function 
void handleRequests(socket_ptr sock); 

private: 
// session data here 
} 

typedef boost::shared_ptr<Session> SessionPtr; 

"서버"기능에서 루프가 새로운 객체를 생성 받아들이고 새로운 스레드에 전달 : 수에 대한

SessionPtr newSession(new Session()); 

boost::thread acceptThread(boost::bind(&Session::handleRequests, newSession, sock)); 

죄송합니다 코드의 실수, 나는 그것을 테스트 할 수없는 나의 개발 환경에서 멀다. separatly 향상 참조 여러 연결을 처리하는 더 우아한 솔루션 :: ASIO 예 "채팅 서버"를

: http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/example/chat/chat_server.cpp

+0

고마워, 나는 당신의 충고를 따랐지만, 지금은 Session 클래스의 새로운 인스턴스, 그리고 새로운 배열이 사용자가 요청을 입력 할 때마다 만들어지는 것 같습니다. 내 현재 코드는 다음과 같습니다. [link] (http://pastebin.com/m4GqMDqa) – user1042840

+0

답변과 지연에 늦어서 죄송합니다. 나에게 고객 코드를 보여주십시오. – vladv

관련 문제