0

プログラムがあり、ポート 200 でリッスンしています。クライアントが接続された後、クライアントから受信したすべてのデータが std::cout に書き込まれます。クライアントからデータを取得中にエラーが発生した場合は、ホスティングを再開したいと考えています。

ServerSocket sock;
while(true)
{
    try
    {
        uint8 buff[1000];
        std::cout << "hosting..." << std::endl;
        sock.Host(port);

        while(true)
        {
            size_t ret = sock.GetData(buff, 1000);
            buff[ret] = '\0';
            std::cout << buff << std::endl;
        }
    }
    catch(const SocketException& se)
    {
        std::cout << se.What() << std::endl;
    }
}

これに初めて接続したときは、すべて問題ありません。クライアントを閉じると、SocketException が発生します (したがって、新しいホスティングが開始されます)。

ホスト関数:

    m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

m_address.sin_family = AF_INET;
m_address.sin_port = htons(port);
m_address.sin_addr.S_un.S_addr = INADDR_ANY;

int optval = 1;
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof(int));

int retval = bind(m_socket, reinterpret_cast<sockaddr*>(&m_address), sizeof(m_address));

if(retval == SOCKET_ERROR)
    throw SocketException("bind() error", __FUNCTION__, WSAGetLastError());

retval = listen(m_socket, SOMAXCONN);

if(retval == SOCKET_ERROR)
    throw SocketException("listen() error", __FUNCTION__, WSAGetLastError());

m_socket = accept(m_socket, NULL, NULL);

if(m_socket == INVALID_SOCKET)
    throw SocketException("accept() error", __FUNCTION__, WSAGetLastError());

エラーの直後にバインドしたいので、setsockopt 行が必要です (そして、最後のホスティング ソケットは TIME_WAIT 状態ですか?)。setsockopt がないと bind() エラーが発生します。したがって、setsockopt を使用すると、ポートで問題なくホストできます。ただし、クライアントを再起動してホストに接続しようとすると、エラーは発生せず、データを再度送信できます。ただし、プログラムは着信接続を受け入れません(着信接続を待機している accept(m_socket, NULL, NULL); 行でスタックしています)。クライアントは何らかの形で古いソケットに接続できると思います。それは可能ですか?

(注: WSACleanup(); WSAStartup(MAKEWORD(2, 2), &m_wsaData); 行をホスト関数に追加すると、すべてが意図したとおりに機能します。理由はわかりません。WSACleanup();WSAStartup(MAKEWORD(2) , 2), &m_wsaData); は、この問題を調査するために作成したサンプル プログラムでのみ役立ちます。元のプログラムでは、2 行が機能していません。)

4

1 に答える 1

1

あなたは、接続ごとに呼び出しbind()ています。サーバーの起動時に and を1回実行し、その後は繰り返しのみ呼び出す必要がありますlisten()bind()listen()accept()

また、適切に行うには、呼び出しごとに新しいスレッドを生成する必要がありますaccept()。そうしないと、サーバーへの接続を開いて何も送信しないだけで、サーバーを DOS できるようになります。

于 2012-09-28T20:10:03.393 に答える