3

TCP サーバーに問題があります。クライアントに応答するために複数のポートでリッスンしたいと思います。それは一種のイベントベースでなければなりません。各ポートは、別のタイプの応答を示します。epoll、poll、select、またはマルチスレッドについてよく読んでいます。私は、Unix Network Programming のような本からの多くの例を使用しようとしました。しかし、おそらくいくつかのトリガー キーワードが必要です。どうすれば適切に開始できますか?

私の質問が理解しやすいことを願っています。それぞれの答えに感謝します!

それを絞り込むために、私のアイデアがあります... 私はこれについて考え始めました:

多数のサーバーを含む「サーバー マネージャー」を使用している場合、次のようにできますか?

CreateSockets(ServerList); CheckSockets(SocketList, master_set);

サーバー マネージャー内: 1) すべてのサーバー ソケットを作成する for ループ (関数: socket/setsockopt/ioctl/bind/listen)

void CreateSockets(map<int,ServerType> ServerList)
{
    fd_set        master_set;
    map<int,ServerType>::iterator it;
    map<int,int> SocketList;
    for (it= ServerList.begin();it!= ServerList.end();it++)
    {
        listen_sd = socket(AF_INET, SOCK_STREAM, 0);
        if (listen_sd < 0)
        {
            perror("socket() failed");
            exit(-1);
        }
        rc = setsockopt(listen_sd, SOL_SOCKET,  SO_REUSEADDR,
                (char *)&on, sizeof(on));
        if (rc < 0)
        {
            perror("setsockopt() failed");
            close(listen_sd);
            exit(-1);
        }
        rc = ioctl(listen_sd, FIONBIO, (char *)&on);
        if (rc < 0)
        {
            perror("ioctl() failed");
            close(listen_sd);
            exit(-1);
        }
        memset(&addr, 0, sizeof(addr));
        addr.sin_family      = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port        = ((*it).second->Port);
        rc = bind(listen_sd,(struct sockaddr *)&addr, sizeof(addr));
        if (rc < 0)
        {
            perror("bind() failed");
            close(listen_sd);
            exit(-1);
        }
        rc = listen(listen_sd, 32);
        if (rc < 0)
        {
            perror("listen() failed");
            close(listen_sd);
            exit(-1);
        }
        SocketList.insert(make_pair(((*it).second->Port),listen_sd));
        FD_ZERO(&master_set);
        max_sd = listen_sd;
        FD_SET(listen_sd, &master_set);
    }
}

次へ: 2) サーバー マネージャー内でいくつかのイベントを待機する方法 (ソケット記述子のリストで選択)

void CheckSockets(map<int,int> SocketList, fd_set master_set)
 {
    fd_set working_set;
    do
    {
        memcpy(&working_set, &master_set, sizeof(master_set));
        ready_descriptors = select(max_sd + 1, &working_set, NULL, NULL, NULL);

        if (ready_descriptors >0)
        {
            desc_ready = rc;
            for (i=0; i <= max_sd  &&  desc_ready > 0; ++i)
            {
                if (FD_ISSET(i, &working_set))
                {
                    desc_ready -= 1;
                    if (i == listen_sd)
                    {
                        do
                        {
                            new_sd = accept(listen_sd, NULL, NULL);
                            if (new_sd < 0)
                            {
                                //error
                            }
                            FD_SET(new_sd, &master_set);
                            if (new_sd > max_sd)
                                max_sd = new_sd;
                        } while (new_sd != -1);
                    }
                    else
                    {
                        do
                        {
                            //Go into server and recv and send ( Input Parameter = i)
                            CheckServer(i);
                        } while (TRUE);
                    }
                }
            }
        }
        else {endserver=true;}
    }while(endserver=true;)

}

3) サーバーに入り、質問を処理します (受信/送信)????

    void CheckServer( int sd)
 {
    rc = recv(sd, buffer, sizeof(buffer), 0);

    //some stuff in between

    rc = send(i, buffer, len, 0); 
 }

これは機能しますか?

一部のパーツは、IBM ノンブロッキング IO ソース コードから使用および変更されています。


いつもお世話になっております。私は何かを成し遂げることができましたが、まだうまくいかないことが1つあります。

私が今までやったこと:

1) 個々のサーバーのコンストラクターには、ソケット操作が含まれます。2) ソケット ID を返し、サーバー マネージャー内に保存できます。3) マネージャには、ソケットのイベントをチェックする select コマンドを含む for ループがあります。4) 何かが発生した場合、影響を受けるすべてのソケットが順次応答します。

私の問題は次のとおりです。

サーバーからデータを要求している間、常に接続と切断を行っていれば問題なく動作します。接続が保持されるようにクライアントが構成されている場合、コードが切断を待機しているため、すべてがブロックされます。

各部分のコード スニペットは次のとおりです。

1)

       Server::Server() 
    {

    listen_sd = socket(AF_INET, SOCK_STREAM, 0);
    ret = setsockopt(listen_sd, SOL_SOCKET,  SO_REUSEADDR,(char *)&on, sizeof(on));
    ret = ioctl(listen_sd, FIONBIO, (char *)&on);

    memset(&addr, 0, sizeof(addr));
    addr.sin_family      = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port        = htons(Server_Port);
    ret = bind(listen_sd,(struct sockaddr *)&addr, sizeof(addr));
    ret = listen(listen_sd, 32);
    Socket = listen_sd;
}

2)

Socket= new_Server->GetSocket();
SocketList.insert(make_pair(Socket,new_Server->ServerID));

3)

 while (TRUE)
    {
        FD_ZERO(&working_set);
        for (i=0;i < max_conn;i++) 
{
            if (SocketArray[i] >= 0) {FD_SET(SocketArray[i], &working_set);}
        }

        ret = select(max_sd+1, &working_set, NULL, NULL, NULL);

    desc_ready= ret;
        for (i=0; i <= max_sd  &&  desc_ready > 0; ++i)
        {

            if (FD_ISSET(i, &working_set)) //jeder Peer der was hat
            {
                desc_ready -= 1;
//delete all loops to get the correct object 
                        (Server).second->DoEvent(i);

            }
        }
    }

4)

new_sd = accept(new_sd, NULL, NULL);
    if (new_sd < 0)
    {
        if (errno != EWOULDBLOCK)
        {
            perror("  accept() failed");
        }
    }
do
{


    rc = recv(new_sd, buffer, sizeof(buffer), 0);
//edit datastream and create response
            rc = send(new_sd, buffer, len, 0);
        if (rc < 0)
        {
            perror("  send() failed");
            close_conn = TRUE;
            break;
        }

    }while (TRUE);

ここでコードを短くするために、エラー処理やリッスン/バインドなどを削除するだけです...もともとそこにあります。

4

1 に答える 1

2

おおよその手順は次のとおりです。複数の TCP サーバー (別名サーバー ソケット) で各ポートをリッスンできます。次に、select() を使用して、これらのサーバー ソケットごとにファイル記述子を渡すことができます。これらのいずれかで接続を取得すると、select は読み取りイベントを返し、接続しているサーバー ソケットの fd をマークします。そのサーバー fd で accept() を呼び出す必要があります。

単一の TCP ソケットを複数のポートでリッスンすることはできません。

于 2013-08-27T12:51:31.230 に答える