2

Libevent は素晴らしく、今のところ気に入っています。ただし、エコー サーバーでは、書き込みは 2 回目の書き込みでのみソケットに送信されます。私の執筆は別のスレッド、つまりデータベースと通信し、最小限のデータ マッサージを行うポンプ スレッドからのものです。

書き込み用のコールバックを設定して、これを確認しました。

bufferevent_setcb( GetBufferEvent(), DataAvailable, DataWritten, HandleSocketError, this );

bufferevent_flush( m_bufferEvent, EV_READ|EV_WRITE, BEV_NORMAL ) を呼び出しても効果がないようです。

どこかで吹き飛ばした場合に備えて、ここにセットアップがあります。ヘルプを得るために、コード ベースのオーバーヘッドを大幅に簡素化しました。これには、ソケットの初期化、スレッドの初期化などが含まれます。これはマルチスレッド アプリであるため、問題が発生する可能性があります。私はこれから始めます:

m_LibEventInstance = event_base_new();
evthread_use_windows_threads();
m_listener = evconnlistener_new_bind( m_LibEventInstance, 
         OnAccept, 
         this,
         LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | LEV_OPT_REUSEABLE, 
         -1,// no maximum number of backlog connections
         (struct sockaddr*)&ListenAddress, socketSize );

   if (!m_listener) {
          perror("Couldn't create listener");
          return false;
   }
   evconnlistener_set_error_cb( m_listener, OnSystemError );

私の知る限り、これはサンプルからのコピーと貼り付けなので、うまくいくはずです。私の OnAccept は次のことを行います。

void  OnAccept( evconnlistener* listenerObj, evutil_socket_t newConnectionId, sockaddr* ClientAddr, int socklen, void* context )
{
    // We got a new connection! Set up a bufferevent for it. 
    struct event_base*  base = evconnlistener_get_base( listenerObj );
    struct bufferevent* bufferEvent = bufferevent_socket_new( base, newConnectionId, BEV_OPT_CLOSE_ON_FREE );

   bufferevent_setcb( GetBufferEvent(), DataAvailable, DataWritten, 
                                   HandleSocketError, this );

  // We have to enable it before our callbacks will be called. 
  bufferevent_enable( GetBufferEvent(), EV_READ | EV_WRITE );

  DisableNagle( m_connectionId );
}

ここでは、入ってくるデータに応答し、後で処理するためにバッファに格納するだけです。これはマルチスレッド アプリケーションなので、後でデータを処理したり、メッセージを送信したり、クライアントに応答を返したりします。

void     DataAvailable( struct bufferevent* bufferEventObj, void* arg )
{
const U32   MaxBufferSize = 8192;
   MyObj*   This = (MyObj*) arg;
   U8          data[ MaxBufferSize ];
   size_t      numBytesreceived;

   /* Read 8k at a time and send it to all connected clients. */
   while( 1 )
   {
      numBytesreceived = bufferevent_read( bufferEventObj, data, sizeof( data ) );
      if( numBytesreceived <= 0 ) // nothing to send
      {
         break;
      }

      if( This )
      {
         This->OnDataReceived( data, numBytesreceived );
      }
   }
}

最後に、データを検索したら、バッファにパッケージ化し、スレッド化されたタイムスライスでこれを行います。

bufferevent_write( m_bufferEvent, buffer, bufferOffset );

初めて送信することはありません。送信するには、データでいっぱいの 2 番目のバッファーを送信する必要があります。

この振る舞いは私を殺し、私はそれに多くの時間を費やしました. 何か案は?

//------------------------------------------------ -------

私は最終的にあきらめて、代わりにこのハックを使用しました... libevent がソケットに書き込んでいない理由を説明するのに十分な情報がありませんでした。これはうまくいきます。

int result = send( m_connectionId, (const char* )buffer, bufferOffset, 0 );
4

1 に答える 1

-1

私も問題に遭遇しました!私はこの問題に 1 日を費やしました。最後に、私はそれを解決しました。

スレッドを呼び出すとevent_base_dispatch、セマフォが起動するまでスリープ状態になります。そのため、スリープ時に を呼び出すbufferevent_writeと、bufferevent の fd がイベント リストに追加されますが、次回まで epoll になりません。したがって、 を呼び出した後、セマフォを送信してディスパッチ スレッドを起動する必要がありますbufferevent_write。使用できる方法は、イベント バインド ペア ソケットをセットアップし、それを に追加することevent_baseです。次に、ディスパッチ スレッドを起動する必要があるときにいつでも 1 バイトを送信します。

于 2016-04-07T09:26:47.163 に答える