1

私はソケットを使用するアプリケーションを実行しているため、ソケットハンドルを配列に保持しています。次のコードがあります。

while(0 == 0){
    int * tx = (int*)(malloc((nr_con + 2) * sizeof(int)));
    if (conexiuni != NULL)
    {
        syslog(LOG_NOTICE,"Ajung la eliberare %d",nr_con);
        memcpy(&tx[0],&conexiuni[0],(sizeof(int) * (nr_con)));
        syslog(LOG_NOTICE,"Ajung la eliberare %d",nr_con);
        free(conexiuni);
    }
    conexiuni = tx;

    syslog(LOG_NOTICE,"Ajung la mama %d",nr_con);
    //The line bellow causes a segfault at second connection
    if ((conexiuni[nr_con] = accept(hsock,(sockaddr*)(&sadr),&addr_size)) != -1)
    {
        nr_con++;
        syslog(LOG_NOTICE,"Primesc de la %s",inet_ntoa(sadr.sin_addr));
        syslog(LOG_NOTICE,"kkt %d",conexiuni[nr_con - 1]);
        int * sz = (int*)malloc(sizeof(int));
        *sz = conexiuni[nr_con - 1];
        syslog(LOG_NOTICE,"after %d",*sz);
        pthread_create(&tidi,0,&ConexiuniHandler, sz);
    }
}

配列を割り当てるときに 2 回目に接続すると、プログラムがクラッシュします。私は何を間違っていますか?Windows で同じコードを試してみましたが、うまく動作しますが、Linux ではクラッシュします。

4

2 に答える 2

4

を使用しstd::vectorます。

動的サイズの配列をカプセル化するシーケンス コンテナー。

于 2012-09-15T15:40:51.483 に答える
2

私はあなたがしたいことは接続を受け入れるサーバーを持っていることだと思います、そして次に接続が受け入れられると、あなたはその接続要求を処理するためにスレッドを開始します。したがって、acceptを実行するたびに、スレッドを起動してソケットハンドルを指定する必要があります。また、新しい接続要求を受け入れると動的に増加する配列内のすべてのソケットハンドルに対応しています。

以下は推奨される方法です。私はテストを行っておらず、このコードセグメントをコンパイルしたこともありませんが、ここから始めてください。私が行っていることの1つは、配列のサイズを変更するたびに、ソケットハンドルの配列を16ブロックずつ増やすことです。これを行っているのは、メモリマネージャの作業が少し簡単になり、への呼び出し回数を減らすことで断片化の量を減らすことができるためmalloc()です。

int nr_con = 0;      // we start off with no connections
int block_con = 16;  // number of blocks to allocate each time we increase the array
SOCKET  *conexiuni = malloc ((nr_con + block_con) * sizeof(SOCKET));
while(1) {
    syslog (LOG_NOTICE, "Ajung la mama %d", nr_con);

    // wait for a connection request to come in.  if it does, log the request
    // then create a thread to handle the request providing the socket to the thread.
    // we are keeping an array of the sockets that is dynamically increased so
    // we will allocate blocks of 16 at a time as we lengthen the array.
    if ((conexiuni[nr_con] = accept (hsock, (sockaddr*)(&sadr), &addr_size)) != -1)
    {
        block_con--;
        if (block_con < 1) {
        {
            // so lets add another block to our array by allocating the memory
            // then copying the current array to the new memory area then freeing
            // the old memory area which is no longer needed.
            block_con = 16;
            SOCKET *pTemp = malloc(nr_con + block_con) * sizeof(SOCKET));
            syslog (LOG_NOTICE, "Ajung la eliberare %d", nr_con);
            memcpy (pTemp, conexiuni, (sizeof(SOCKET) * (nr_con + 1)));
            syslog (LOG_NOTICE, "Ajung la eliberare %d", nr_con);
            free (conexiuni);
            conexiuni = pTemp;
        }
        syslog (LOG_NOTICE, "Primesc de la %s", inet_ntoa(sadr.sin_addr));
        syslog (LOG_NOTICE, "kkt %d", conexiuni[nr_con]);

        SOCKET  *sz = conexiumi + nr_con;
        syslog (LOG_NOTICE, "after %d", *sz);

        // start the thread which is to service this connection request.
        pthread_create (&tidi, 0, &ConexiuniHandler, sz);
        nr_con++;
    }
}

ただし、このようなものにはいくつかの問題があります。まず、上記の例では、メモリ不足エラーを処理しmalloc()ていませんが、メモリ要求を提供できないため、NULLポインタを返す必要があります。

2番目の問題は、配列が動的に拡張される前にスレッドがソケットへのポインターにアクセスせず、動的な再割り当て中に解放されたために提供されたポインターが無効になる可能性です。したがって、多くの接続がすぐに着信する場合、これは問題になる可能性があります。少なくとも、スレッドが最初に行うべきことは、ソケットハンドルのローカルコピーを作成することです。

もう1つの質問は、アレイに戻って、どのソケットがまだ有効で開いているか、接続が閉じているとどのソケットが古くなっているかを判断する方法です。サーバーが稼働してから数日後にメモリが不足するまで、接続要求が入ってくるときに動的にスペースを割り当て続けますか?

intを使用するのではなく、実際のデータ型であるSOCKETを使用する必要があります。ほとんどの場合、SOCKETは実際にはintであると認識していますが、通常、これらの問題については正確である方が適切です。

于 2012-09-15T16:27:51.350 に答える