2011-11-12 4 views
1

私はC++を学びましたが、今度は何かネットワークプログラミングを学びたいと思います。私は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関数で処理され、その後アレイに書き込まれるか、配列から読み取られます。問題は、すべてのクライアントが同じグローバルアライを使用していることです。つまり、あるクライアントが特定のIDの下に何かを保存した場合、他のすべてのクライアントは同じアレイにアクセスするため、そのクライアントを読み取ることができます。私は、どうやって配列を別のクライアントに関連付けることができ、新しいクライアントが接続するときに新しい配列を作成するのだろうか?

+2

どのクラスにクライアントをカプセル化についてはどうですか? – netcoder

答えて

0

セッションデータをクラスにカプセル化し、接続ごとに個別のセッションオブジェクトを作成する方法についてはどうか。約それは次のようになります。

Sessionクラスの定義:「サーバー」機能で

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

ありがとう、私はあなたの助言に従っていましたが、今度は、セッションクラスの新しいインスタンス、したがって新しい配列が、ユーザーがリクエストを入力するたびに作成されるようです。私の現在のコードはここにあります:[link](http://pastebin.com/m4GqMDqa) – user1042840

+0

答えが遅れて申し訳ありません。私にクライアントのコードを表示してください。 – vladv

関連する問題