0

ソケットに接続できるサーバー上で、マネージャークライアントの単純な CRUD を作成しようとしています (C では、あまり慣れていない言語ですが、選択の余地はありません)。サーバーは、セッション ID を使用して、同時に 10 の同時接続を保持します。問題は、10 個のクライアントを追加した後にリストを印刷すると、10 回の同じオブジェクト (または同じ ID を持つ 10 個のオブジェクト、これは私が少し混乱している場所です) のリストが表示されることです。

これは、マネージャー クライアントの構造体を宣言し、リスト (10 個を保持できる) を宣言する方法です。

typedef struct Mana_client {
    int client_id;
    int timestamp_connection;
    char privilege_level;
}Mana_client;

Mana_client *mana_client_list[10];
srand(time(NULL)); // is called once when initializing the thread.

これは、「クライアントをリストに追加する」と書いた方法です。

int add_mana_client()
{
    int i=0;
    int client_id = 0;
    int timestamp = 0;
    Mana_client client = { client_id, timestamp, 1};
    client_id = rand()%100000;
    timestamp = time(NULL);
    client.client_id =  &client_id;
    client.timestamp_connection = &timestamp;
    for(i=0; i <10; i++)
    {
        if(mana_client_list[i] == NULL){
            printf("%u. Empty spot in list\n", i);
            if(!contains_mana_client_id(client_id)){
                printf("%u. Adding client... (with ID%u)\n", i, client.client_id);
                mana_client_list[i] = &client;
                return client_id;
            }
        }
    }
    return 0;
}

これは、同じ ID を持つクライアントが既にリストにあるかどうかを確認する方法です。

int contains_mana_client_id(int id)
{
    int i=0;
    for(i=0; i <10; i++)
    {
        if(mana_client_list[i] != NULL){
            if(id == mana_client_list[i]->client_id){
                printf("%u. Client with ID=%u found.\n", i, id);
                return 1;
            }
        }
    }
    return 0;
}

次に、リストとそのクライアントを確認します。

void print_mana_client_list()
{
    int i=0;
    printf("Printing list of mana clients...\n\n");
    for(i=0; i <10; i++)
    {
        if(mana_client_list[i] != NULL){
            printf("%u. Client with ID=%u.\n", i, mana_client_list[i]->client_id);
        }else{
            printf("%u. Empty.\n", i);
        }
    }
}

クライアントを追加するメソッドを 12 回連続して実行し、リストを出力すると、次の出力が得られます。

  1. リストの空のスポット
  2. クライアントを追加しています... (ID94630956) 管理クライアントが追加されました (ID=41)。
  3. リストの空のスポット
  4. クライアントを追加しています... (ID94630956) 管理クライアントが追加されました (ID=18467)。
  5. リストの空のスポット
  6. クライアントを追加しています... (ID94630956) 管理クライアントが追加されました (ID=6334)。
  7. リストの空のスポット
  8. クライアントを追加しています... (ID94630956) 管理クライアントが追加されました (ID=26500)。
  9. リストの空のスポット
  10. クライアントを追加しています... (ID94630956) 管理クライアントが追加されました (ID=19169)。
  11. リストの空のスポット
  12. クライアントを追加しています... (ID94630956) 管理クライアントが追加されました (ID=15724)。
  13. リストの空のスポット
  14. クライアントを追加しています... (ID94630956) 管理クライアントが追加されました (ID=11478)。
  15. リストの空のスポット
  16. クライアントを追加しています... (ID94630956) 管理クライアントが追加されました (ID=29358)。
  17. リストの空のスポット
  18. クライアントを追加しています... (ID94630956) 管理クライアントが追加されました (ID=26962)。
  19. リストの空のスポット
  20. クライアントを追加しています... (ID94630956) 管理クライアントが追加されました (ID=24464)。

管理クライアントが追加されました (ID=0)。

管理クライアントが追加されました (ID=0)。

mana クライアントのリストを印刷しています...

  1. ID=3435973836 のクライアント。
  2. ID=3435973836 のクライアント。
  3. ID=3435973836 のクライアント。
  4. ID=3435973836 のクライアント。
  5. ID=3435973836 のクライアント。
  6. ID=3435973836 のクライアント。
  7. ID=3435973836 のクライアント。
  8. ID=3435973836 のクライアント。
  9. ID=3435973836 のクライアント。
  10. ID=3435973836 のクライアント。

個人的には、問題はオブジェクト/値を保存または渡す方法に関連していると思いますが、完全にはわかりません。これに関する助けをいただければ幸いです。

4

1 に答える 1

1

それは、それら同じだからです。あなたがするとき

mana_client_list[i] = &client;

常にローカル変数へのポインターを使用します。代わりに、ループ内の反復ごとに構造体の新しいインスタンスを作成する必要があります。そのmallocためには、構造体にメモリを割り当てるために使用する必要があります。free終わったらその思い出を忘れないでください。

これにより、別の問題も解決されます。つまり、ポインターをローカル変数に保存し、関数add_mana_clientが戻るとスコープ外になります。関数が返された後にそのポインターを使用することは、未定義の動作の場合であり、うまくいくのは幸運です。


mana_client_list[i] = &client;現在のコードに多くの変更を加えることなく、現在の行を置き換える次のコードのような簡単な方法があります。

mana_client_list[i] = malloc(sizeof(Mana_client));
*mana_client_list[i] = client;

これにより、新しい構造体が割り当てられ、既に初期化されている構造体がその新しい構造体にコピーされます。

于 2013-11-05T12:12:14.547 に答える