Linux Proactor测试程序

Linux C/C++进阶学习路径:从系统编程到AI基础设施实战 在计算机系统开发领域,深入理解底层原理是构建高性能、高可靠性软件的基础。系统编程涉及对操作系统内核、硬件资源和进程间通信的直接操控,其核心在于掌握内存管理、并发控制和I/O模型等机制。这种底层掌控能力为开发数据库、消息队列、搜索引擎等基础设施软件提供了技术保障,尤其在追求极致性能的场景中价值凸显。现代C++通过RAII、移动语义等特性提升了资源管理安全性和运行效率,而epoll等I/O多路复用技术则成为高并发服务器的工程实践关键。这些技术共同支撑了AI基础设施、音视频编解码、嵌入式系统等硬核方向的应用需求, 阅读详情

    虽然linux 2.6内核将对aio的支持集成到内核中,但linux 2.6内核aio对socket的支持却不是真正的异步的。对socket的异步IO请求在内核中自动被转换成同步的调用。如果先对一个socket提交一个读操作,然后提交一个写操作,那么写操作只有在读操作完整之后才能执行。这对Proactor在Linux下的实际应用有严重的影响。ace自带一个测试程序$ACE_ROOT/example/Reactor/Proactor/test_proactor2.cpp。但该测试程序的测试成功基本上只意味着Proactor能在Linux下编译并运行。本文对该测试用来进行加强,如果本测试程序能测试通过,那就意味着Proactor在Linux能提供实际的应用支持。

编译命令如下:

g++ -o test_proactor21 test_proactor21.cpp -nostartfiles  -I/usr/local/include -L/usr/local/lib -lACE -lpthread

代码如下:

// test_proactor2.cpp,v 1.8 2003/11/10 01:48:03 dhinton Exp

// ============================================================================
//
// = LIBRARY
//    examples
//
// = FILENAME
//    test_proactor2.cpp
//
// = DESCRIPTION
//    Alexander Libman <Alibman@baltimore.com> modified
//    <test_proactor> and made this test. Instead of writing received
//    data to the file, the receiver sends them back to the
//    sender,i.e. ACE_Asynch_Write_File wf_  has been changed to
//    ACE_Asynch_Write_Stream wf_.
//
// = AUTHOR
//    Irfan Pyarali <irfan@cs.wustl.edu> and Alexander Libman
//    <Alibman@baltimore.com>.
// ============================================================================

#include "ace/Signal.h"

#include "ace/Service_Config.h"
#include "ace/Proactor.h"
#include "ace/POSIX_CB_Proactor.h"
#include "ace/Asynch_IO.h"
#include "ace/Asynch_IO_Impl.h"
#include "ace/Asynch_Acceptor.h"
#include "ace/INET_Addr.h"
#include "ace/SOCK_Connector.h"
#include "ace/SOCK_Acceptor.h"
#include "ace/SOCK_Stream.h"
#include "ace/Message_Block.h"
#include "ace/Get_Opt.h"

#ifndef WIN32
#include <netinet/tcp.h>
#endif

// FUZZ: disable check_for_streams_include
#include "ace/streams.h"

#include "ace/Task.h"
#include "ace/OS_main.h"

ACE_RCSID(Proactor, test_proactor2, "test_proactor2.cpp,v 1.27 2000/03/07 17:15:56 schmidt Exp")

#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)))
  // This only works on Win32 platforms and on Unix platforms supporting
  // POSIX aio calls.

#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)

#include "ace/WIN32_Proactor.h"

#elif defined (ACE_HAS_AIO_CALLS)

#include "ace/POSIX_Proactor.h"

#endif

  //  Some debug helper functions
  int DisableSignal ( int SigNum );
int PrintSigMask ();

#define  COUT(X)  cout << X ; cout.flush ();

// Host that we're connecting to.
static ACE_TCHAR *host = 0;

// duplex mode: ==0 half-duplex
//              !=0 full duplex
static int duplex = 0 ;

static int init_method = 0;

// number threads in the Proactor thread pool
static int nThreads = 1;

// Port that we're receiving connections on.
static u_short port = ACE_DEFAULT_SERVER_PORT;

// Size of each initial asynchronous <read> operation.
static int initial_read_size = BUFSIZ;

static int counter1 = 0 ;

#define MyMutex ACE_Recursive_Thread_Mutex
//#define MyMutex ACE_Thread_Mutex
//#define MyMutex ACE_Null_Mutex

//--------------------------------------------------------------------------
// MyTask plays role for Proactor threads pool
//--------------------------------------------------------------------------
class MyTask: public ACE_Task<ACE_MT_SYNCH>
{

public:

  int svc (void) ;
};


int MyTask::svc (void )
{
  ACE_DEBUG ((LM_DEBUG, "(%t) MyTask started/n"));

  while ( ACE_Proactor::event_loop_done () == 0 )
    {
      ACE_Proactor::run_event_loop ();
    }

  ACE_DEBUG ((LM_DEBUG, "(%t) MyTask finished/n"));
  return 0 ;
}

//-----------------------------------------------------------
//  Receiver
//-----------------------------------------------------------
class Receiver : public ACE_Service_Handler
{
public:

  Receiver (void);
  ~Receiver (void);

  virtual void open (ACE_HANDLE handle,
                     ACE_Message_Block &message_block);
  // This is called after the new connection has been accepted.

protected:
  // These methods are called by the framework

  virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result
                                   &result);
  // This is called when asynchronous <read> operation from the socket
  // complete.

  virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result
                                    &result);
  // This is called when an asynchronous <write> to the file
  // completes.

private:
  int  initiate_read_stream  (void);
  int  initiate_write_stream (ACE_Message_Block & mb, int nBytes );
  bool check_destroy () ;

  ACE_Asynch_Read_Stream rs_;
  ACE_Asynch_Write_Stream ws_;
  ACE_HANDLE handle_;
  MyMutex m_Mtx ;
  long    nIOCount ;
  static long nSessions ;
};


long Receiver::nSessions = 0 ;

Receiver::Receiver (void)
  : handle_ (ACE_INVALID_HANDLE),
    nIOCount ( 0 )
{
  ACE_Guard<MyMutex> locker (m_Mtx) ;
  nSessions ++ ;
  ACE_DEBUG ((LM_DEBUG, "Receiver Ctor nSessions=%d/n", nSessions ));
}

Receiver::~Receiver (void)
{
  ACE_Guard<MyMutex> locker (m_Mtx) ;
  nSessions -- ;
  ACE_OS::closesocket (this->handle_);
  ACE_DEBUG ((LM_DEBUG, "~Receiver Dtor nSessions=%d/n", nSessions ));
}

//---------------------------------------------------------------------
//  return true if we alive, false  we commited suicide
//
//---------------------------------------------------------------------
bool Receiver::check_destroy ()
{
  {
    ACE_Guard<MyMutex> locker (m_Mtx) ;

    if ( nIOCount > 0 )
      {
        return true ;
      }
  }

  delete this ;
  return false ;
}


void Receiver::open (ACE_HANDLE handle,
                     ACE_Message_Block &message_block)
{
  ACE_UNUSED_ARG (message_block);

  ACE_DEBUG ((LM_DEBUG,
              "%N:%l:Receiver::open called/n"));


  this->handle_ = handle;

  int nodelay = 1;
  ACE_SOCK_Stream option_setter (handle);
  if (-1 == option_setter.set_option (ACE_IPPROTO_TCP,TCP_NODELAY,&nodelay,sizeof (nodelay)))
   ACE_ERROR ((LM_ERROR, "%p/n", "set_option"));

  if (this->ws_.open (*this, this->handle_ ) == -1)
    {
      ACE_ERROR ((LM_ERROR,
                  "%p/n",
                  "ACE_Asynch_Write_Stream::open"));

    }
  else if (this->rs_.open (*this, this->handle_) == -1)
    {
      ACE_ERROR ((LM_ERROR,
                  "%p/n",
                  "ACE_Asynch_Read_Stream::open"));
    }
  else
    {
      initiate_read_stream ();
    }


  check_destroy ();
}

int Receiver::initiate_read_stream (void)
{
  ACE_Guard<MyMutex> locker (m_Mtx) ;

  // Create a new <Message_Block>.  Note that this message block will
  // be used both to <read> data asynchronously from the socket and to
  // <write> data asynchronously to the file.
  ACE_DEBUG ((LM_DEBUG,
              "initiate_read_stream called/n"));


  ACE_Message_Block *mb = 0;
  ACE_NEW_RETURN (mb,
                  ACE_Message_Block (BUFSIZ + 1),
                  -1);

  // Inititiate read
  if (this->rs_.read (*mb, mb->size ()- 1) == -1)
    {
      mb->release () ;
      ACE_ERROR_RETURN ((LM_ERROR,
                         "%p/n",
                         "ACE_Asynch_Read_Stream::read"),
                        -1);
    }

  nIOCount++ ;
  return 0;
}

int Receiver::initiate_write_stream (ACE_Message_Block & mb, int nBytes )
{
  ACE_Guard<MyMutex> locker (m_Mtx) ;
  if (this->ws_.write (mb , nBytes ) == -1)
    {
      mb.release ();
      ACE_ERROR_RETURN((LM_ERROR,
                        "%p/n",
                        "ACE_Asynch_Write_File::write"),
                       -1);
    }

  nIOCount++ ;
  return 0;
}

void
Receiver::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
{
  ACE_DEBUG ((LM_DEBUG,
              "handle_read_stream called/n"));

  // Reset pointers.
  result.message_block ().rd_ptr ()[result.bytes_transferred ()] =
    '/0';

  ACE_DEBUG ((LM_DEBUG, "********************/n"));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "bytes_to_read", result.bytes_to_read
              ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "handle", result.handle ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "bytes_transfered",
              result.bytes_transferred ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "act", (u_long) result.act ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "success", result.success ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "completion_key", (u_long)
              result.completion_key ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "error", result.error ()));
  ACE_DEBUG ((LM_DEBUG, "********************/n"));
  ACE_DEBUG ((LM_DEBUG, "%s = %s/n", "message_block",
              result.message_block ().rd_ptr ()));

  if ( result.success () && result.bytes_transferred () != 0)
    {
      // Successful read: write the data to the file asynchronously.
      // Note how we reuse the <ACE_Message_Block> for the writing.
      // Therefore, we do not delete this buffer because it is handled
      // in <handle_write_stream>.

      if(this->initiate_write_stream (result.message_block (),

                                      result.bytes_transferred () ) == 0 )
        {
          if ( duplex != 0 )
            {
              // Initiate new read from the stream.
              this->initiate_read_stream () ;
            }
        }
    }
  else
    {
      result.message_block ().release ();
      ACE_DEBUG ((LM_DEBUG,  "Receiver completed/n"));
    }

  {
    ACE_Guard<MyMutex> locker (m_Mtx) ;
    nIOCount-- ;
  }
  check_destroy () ;
}

void
Receiver::handle_write_stream (const ACE_Asynch_Write_Stream::Result
                               &result)
{
  ACE_DEBUG ((LM_DEBUG, "handle_write_stream called/n"));

  ACE_DEBUG ((LM_DEBUG, "********************/n"));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "bytes_to_write",
              result.bytes_to_write ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "handle", result.handle ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "bytes_transfered",
              result.bytes_transferred ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "act", (u_long) result.act ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "success", result.success ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "completion_key", (u_long)
              result.completion_key ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "error", result.error ()));
  ACE_DEBUG ((LM_DEBUG, "********************/n"));

  result.message_block ().release ();

  if (result.success ())
    {
      // This code is not robust enough to deal with short file writes
      // (which hardly ever happen) ;-)
      //ACE_ASSERT (result.bytes_to_write () == result.bytes_transferred ());

      if ( duplex == 0 )
        {
          initiate_read_stream () ;
        }
    }

  {
    ACE_Guard<MyMutex> locker (m_Mtx) ;
    nIOCount-- ;
  }
  check_destroy () ;
}

//-------------------------------------------------------------------------
// Sender:  sends indefinetely welcome message
//  and  recieves it back
//------------------------------------------------------------------------
class Sender : public ACE_Handler
{
public:
  Sender (void);
  ~Sender (void);
  int open (const ACE_TCHAR *host, u_short port);
  void close ();
  ACE_HANDLE handle (void) const;
  void handle (ACE_HANDLE);
 
  int initiate_write_stream (void);

protected:
// These methods are called by the freamwork

virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result
&result);
// This is called when asynchronous reads from the socket complete

virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result
&result);
// This is called when asynchronous writes from the socket complete

 
private:

int initiate_read_stream (void);


ACE_SOCK_Stream stream_;
// Network I/O handle

ACE_Asynch_Write_Stream ws_;
// ws (write stream): for writing to the socket

ACE_Asynch_Read_Stream rs_;
// rs (read file): for reading from the socket

ACE_Message_Block welcome_message_;
// Welcome message

MyMutex m_Mtx ;
long    nIOCount ;
};


#define POST_COMPLETION

#if defined(WIN32) || defined(POST_COMPLETION)

class ACE_POSIX_InitWrite_Notification : public ACE_POSIX_Asynch_Result
{
 Sender *m_sender ;
 
public:
  /// Constructor.
  ACE_POSIX_InitWrite_Notification (Sender *sender,
            const ACE_Handler::Proxy_Ptr &handler_proxy,
                               const void *act = 0,
                               ACE_HANDLE event = ACE_INVALID_HANDLE,
                               int priority = 0,
                               int signal_number = ACE_SIGRTMIN):                   
    ACE_POSIX_Asynch_Result(handler_proxy, act, event, (u_long)0, (u_long)0, priority, signal_number),
    m_sender(sender)
  {
  }

  /// Destructor.
  virtual ~ACE_POSIX_InitWrite_Notification (void)
  {
  }
 
  virtual void complete (size_t bytes_transferred,
                         int success,
                         const void *completion_key,
                         u_long error = 0)
  {
   
   ACE_DEBUG((LM_DEBUG,"ACE_POSIX_InitWrite_Notification::complete called/n"));
   m_sender->initiate_write_stream();
  }
};


struct Event
{
 Sender *sender ; 
};

class EventTask: public ACE_Task<ACE_MT_SYNCH>
{

public:

  int svc (void)
  {
    ACE_Message_Block *msg ;
   while(getq(msg) != -1)
 {
  Event *event = (Event *)msg->base();
  //event->sender->initiate_write_stream();

  ACE_DEBUG((LM_DEBUG,"PostEvent::Handle called/n"));
  //m_sender->initiate_write_stream(); 
  
  static int count = 0 ;
  ACE_DEBUG((LM_DEBUG,"Sleep(%d)/n",count++));
  ACE_OS::sleep(1);
  
  ACE_POSIX_InitWrite_Notification *notify = NULL;
  ACE_NEW_RETURN(notify,ACE_POSIX_InitWrite_Notification(event->sender,(dynamic_cast<ACE_Handler *>(event->sender))->proxy()),-1);
  
  ACE_Proactor *proactor = ACE_Proactor::instance();
  ACE_Proactor_Impl * proactor_impl = proactor->implementation();
  notify->post_completion(proactor_impl);

  delete msg ;
 }
  }   

  void enqueue(Sender *sender)
  {
 ACE_Message_Block *msg ;
 ACE_NEW(msg,ACE_Message_Block(sizeof(Event)));
 Event *event = (Event *)msg->base();
 event->sender = sender ;
 putq(msg);
  }

  void close()
  {
 this->msg_queue()->close();
  }
};


EventTask event_task ;

#endif


static char *data = "Welcome to Irfan World! Irfan RULES here !!/n";

Sender::Sender (void)
  :nIOCount ( 0 )
{
  // Moment of inspiration... :-)
  this->welcome_message_.init (data, ACE_OS::strlen (data));
}

Sender::~Sender (void)
{
  close ();
}

void Sender::close ()
{
  this->stream_.close ();
}

ACE_HANDLE Sender::handle (void) const
{
  return this->stream_.get_handle ();
}

void Sender::handle (ACE_HANDLE handle)
{
  this->stream_.set_handle (handle);
}

int Sender::open (const ACE_TCHAR *host, u_short port)
{
  // Initialize stuff
  // Connect to remote host
  ACE_INET_Addr address (port, host);
  ACE_SOCK_Connector connector;

  if (connector.connect (this->stream_,
                         address) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         "%p/n",
                         "ACE_SOCK_Connector::connect"),
                        -1);
    }

 int nodelay = 1;
 ACE_SOCK_Stream option_setter (stream_.get_handle());
 if (-1 == option_setter.set_option (ACE_IPPROTO_TCP,TCP_NODELAY,&nodelay,sizeof (nodelay)))
  ACE_ERROR ((LM_ERROR, "%p/n", "set_option"));

  // Open ACE_Asynch_Write_Stream
  if (this->ws_.open (*this) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                       "%p/n",
                       "ACE_Asynch_Write_Stream::open"),
                      -1);

  // Open ACE_Asynch_Read_Stream
  if (this->rs_.open (*this) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                       "%p/n",
                       "ACE_Asynch_Read_File::open"),
                      -1);

  // Start an asynchronous transmit file
  if ( this->initiate_write_stream () == -1)
    return -1;

  if ( duplex != 0 )
    {
      // Start an asynchronous read file
      if (this->initiate_read_stream () == -1)
        return -1;
    }

  return 0;
}

int Sender::initiate_write_stream (void)
{
  ACE_Guard<MyMutex> locker (m_Mtx) ;


  welcome_message_.rd_ptr( welcome_message_.base ());
  welcome_message_.wr_ptr( welcome_message_.base ());
  welcome_message_.wr_ptr (ACE_OS::strlen (data));

  if (this->ws_.write (welcome_message_,
                       welcome_message_.length ()
                       ) == -1)
    {
      ACE_ERROR_RETURN((LM_ERROR,
                        "%p/n",
                        "ACE_Asynch_Write_File::write"),
                       -1);
    }

  nIOCount++ ;
  return 0;
}

int Sender::initiate_read_stream (void)
{
  ACE_Guard<MyMutex> locker (m_Mtx) ;

  // Create a new <Message_Block>.  Note that this message block will
  // be used both to <read> data asynchronously from the socket and to
  // <write> data asynchronously to the file.
  ACE_DEBUG ((LM_DEBUG,
              "initiate_read_stream called/n"));


  ACE_Message_Block *mb = 0;
  ACE_NEW_RETURN (mb,
                  ACE_Message_Block (BUFSIZ + 1),
                  -1);

  // Inititiate read
  if (this->rs_.read (*mb, mb->size ()- 1) == -1)
    {
      mb->release () ;
      ACE_ERROR_RETURN ((LM_ERROR,
                         "%p/n",
                         "ACE_Asynch_Read_Stream::read"),
                        -1);
    }

  nIOCount++ ;
  return 0;
}


void Sender::handle_write_stream (const ACE_Asynch_Write_Stream::Result
                                  &result)
{
  ACE_DEBUG ((LM_DEBUG,
              "handle_write_stream called/n"));

  // Reset pointers.
  result.message_block ().rd_ptr (result.message_block ().rd_ptr () -
                                  result.bytes_transferred ());


  ACE_DEBUG ((LM_DEBUG, "********************/n"));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "bytes_to_write",
              result.bytes_to_write ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "handle", result.handle ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "bytes_transfered",
              result.bytes_transferred ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "act", (u_long) result.act ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "success", result.success ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "completion_key", (u_long)
              result.completion_key ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "error", result.error ()));
  ACE_DEBUG ((LM_DEBUG, "********************/n"));
  ACE_DEBUG ((LM_DEBUG, "%s = %s/n", "message_block",
              result.message_block ().rd_ptr ()));

  // Simplify just for Test
  if (result.success () && result.bytes_transferred () != 0)
    {
      if ( duplex != 0 )  // full duplex, continue write
        {
       
         if(init_method == 0)
         {
          ACE_DEBUG((LM_DEBUG,"(%d)handle_write_stream call initiate_write_stream/n",counter1++));  
          ACE_OS::sleep(1);
          initiate_write_stream () ;
         }
         else if(init_method == 1)
         {
          ACE_DEBUG((LM_DEBUG,"(%d)handle_write_stream use ACE_POSIX_InitWrite_Notification/n",counter1++));  
          ACE_POSIX_InitWrite_Notification *notify = NULL;
    ACE_NEW(notify,ACE_POSIX_InitWrite_Notification(this,(dynamic_cast<ACE_Handler *>(this))->proxy()));
 
    ACE_OS::sleep(1);
     
    ACE_Proactor *proactor = ACE_Proactor::instance();
    ACE_Proactor_Impl * proactor_impl = proactor->implementation();
    notify->post_completion(proactor_impl);
   }
   else
   {
     ACE_DEBUG((LM_DEBUG,"handle_write_stream post_event duplex=1/n"));
           event_task.enqueue(this);
   }
 
        }
      else  // half-duplex   read reply, after read we will start
        // write
        {
          initiate_read_stream () ;
        }
    }

  {
    ACE_Guard<MyMutex> locker (m_Mtx) ;
    nIOCount-- ;
  }
}

void
Sender::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
{
  ACE_DEBUG ((LM_DEBUG,
              "handle_read_stream called/n"));

  // Reset pointers.
  result.message_block ().rd_ptr ()[result.bytes_transferred ()] =
    '/0';

  ACE_DEBUG ((LM_DEBUG, "********************/n"));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "bytes_to_read", result.bytes_to_read
              ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "handle", result.handle ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "bytes_transfered",
              result.bytes_transferred ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "act", (u_long) result.act ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "success", result.success ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "completion_key", (u_long)
              result.completion_key ()));
  ACE_DEBUG ((LM_DEBUG, "%s = %d/n", "error", result.error ()));
  ACE_DEBUG ((LM_DEBUG, "********************/n"));
  ACE_DEBUG ((LM_DEBUG, "%s = %s/n", "message_block",
              result.message_block ().rd_ptr ()));

  result.message_block().release ();

  if ( result.success () && result.bytes_transferred () != 0)
    {
      // Successful read: write the data to the file asynchronously.
      // Note how we reuse the <ACE_Message_Block> for the writing.
      // Therefore, we do not delete this buffer because it is handled
      // in <handle_write_stream>.

      if ( duplex != 0 )  // full duplex, continue read
        {
          initiate_read_stream () ;
        }
      else  // half-duplex  writey, after write we will start read
        {
        
         if(init_method == 0)
         {
          ACE_DEBUG((LM_DEBUG,"(%d)handle_write_stream call initiate_write_stream/n",counter1++));  
          initiate_write_stream () ;
         }
         else if(init_method == 1)
         {
          ACE_DEBUG((LM_DEBUG,"(%d)handle_write_stream use ACE_POSIX_InitWrite_Notification/n",counter1++));  
          ACE_POSIX_InitWrite_Notification *notify = NULL;
    ACE_NEW(notify,ACE_POSIX_InitWrite_Notification(this,(dynamic_cast<ACE_Handler *>(this))->proxy()));
   
    ACE_OS::sleep(1);
 
    ACE_Proactor *proactor = ACE_Proactor::instance();
    ACE_Proactor_Impl * proactor_impl = proactor->implementation();
    notify->post_completion(proactor_impl);
   }
   else
   {
  
    ACE_DEBUG((LM_DEBUG,"handle_write_stream post_event duplex=1/n"));
          event_task.enqueue(this);
   }
        }
    }

  {
    ACE_Guard<MyMutex> locker (m_Mtx) ;
    nIOCount-- ;
  }
}

/////////////////////////////////////////////////////////////////////


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

static int
parse_args (int argc, ACE_TCHAR *argv[])
{
  ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("n:p:d:h:m:"));
  int c;

  while ((c = get_opt ()) != EOF)
    switch (c)
      {
      case 'm':
       {
        init_method = ACE_OS::atoi (get_opt.opt_arg ()) ;
       }
       break;
      case 'h':
        host = get_opt.opt_arg ();
        break;
      case 'n':
        nThreads = ACE_OS::atoi (get_opt.opt_arg ()) ;
        break;
      case 'p':
        port = ACE_OS::atoi (get_opt.opt_arg ());
        break;
      case 'd':
        duplex = ACE_OS::atoi (get_opt.opt_arg ());
        break;
      default:
        ACE_ERROR ((LM_ERROR, "%p./n",
                    "usage :/n"
                    "-h <host> for Sender mode/n"
                    "-d <duplex mode 1-on/0-off>/n"
                    "-p <port to listen/connect>/n"
                    "-n <number threads for Proactor pool>/n"
     "-m <method of initiate write stream>/n"
     "   0 - in Proactor thread directory/n"
     "   1 - in Proactor thread indirectory/n"
     "   2 - Event Tash post request to Proactor thread/n"));
        return -1;
      }

  return 0;
}

int main(int argc, char *argv[])
{
  ACE_UNUSED_ARG (initial_read_size);

  if (parse_args (argc, argv) == -1)
    return -1;

#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)

  ACE_WIN32_Proactor *      pImpl = new ACE_WIN32_Proactor;

#elif defined (ACE_HAS_AIO_CALLS)

  //ACE_POSIX_AIOCB_Proactor *  pImpl = new ACE_POSIX_AIOCB_Proactor;
  ACE_POSIX_CB_Proactor *  pImpl = new ACE_POSIX_CB_Proactor;
  //ACE_POSIX_SIG_Proactor *  pImpl = new ACE_POSIX_SIG_Proactor;
#endif

  ACE_Proactor Proactor ( pImpl ,1 );

  ACE_Proactor::instance( & Proactor );


  MyTask  Task1 ;

  if (Task1.activate (THR_NEW_LWP, nThreads ) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR, "%p./n", "main"), -1);
    }

   if (event_task.activate (THR_NEW_LWP, 1 ) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR, "%p./n", "main"), -1);
    }

  Sender sender;
  ACE_Asynch_Acceptor<Receiver> acceptor;

  int Rc = -1 ;

  if ( host == NULL ) // Acceptor
    {
      // Simplify , initial read with  zero size
      Rc = acceptor.open (ACE_INET_Addr (port),0,1);

    }
  else
    {
      Rc = sender.open (host, port);
    }

  if ( Rc == 0 )
    {
      char c ;
      cout << "Press any key to stop and exit=>/n" << flush ;
      cin.clear ();
      cin >> c ;
    }

  ACE_Proactor::end_event_loop () ;

  if ( host != NULL ) // we are sender
    {
      sender.close () ; // disconnect to get reciever error !!!
    }


  event_task.close();

  ACE_Thread_Manager * pTM = ACE_Thread_Manager::instance();

  pTM->wait_task ( & event_task ) ;
  pTM->wait_task ( & Task1 ) ;

  ACE_Proactor::instance( ( ACE_Proactor* )NULL );

  return 0;
}
//--------------------------------------------------------------------
//
//--------------------------------------------------------------------
int DisableSignal ( int SigNum )
{

#ifndef ACE_WIN32
  sigset_t signal_set;
  if ( sigemptyset (&signal_set) == - 1 )
    {
      ACE_ERROR ((LM_ERROR,
                  "Error:(%P | %t):%p/n",
                  "sigemptyset failed"));
    }

  sigaddset (&signal_set, SigNum);

  //  Put the <signal_set>.
  if (ACE_OS::pthread_sigmask (SIG_BLOCK, &signal_set, 0) != 0)
    {
      ACE_ERROR ((LM_ERROR,
                  "Error:(%P | %t):%p/n",
                  "pthread_sigmask failed"));
    }
#else
  ACE_UNUSED_ARG(SigNum);
#endif

  return  1;
}
//--------------------------------------------------------------------
// Get the <signal_set> back from the OS.
//--------------------------------------------------------------------

int PrintSigMask ()
{
#ifndef ACE_WIN32

  sigset_t  mask ;
  int member = 0;

  COUT ( "/n=============Signal Mask==========" )

    if (ACE_OS::pthread_sigmask (SIG_SETMASK, 0, & mask ) != 0)
      {
        ACE_ERROR ((LM_ERROR,
                    "Error:(%P | %t):%p/n",
                    "ACE_OS::pthread_sigmask failed"));
      }
    else  for (int i = 1 ; i < 1000; i++)
      {
        member = sigismember (&mask,i);

        COUT ( "/nSig " )
          COUT ( i )
          COUT ( " is " )
          COUT (member )

          if (member == -1)
            {
              break ;
            }
      }
#endif
  return 0;
}


#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
template class ACE_Asynch_Acceptor<Receiver>;
#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
#pragma instantiate ACE_Asynch_Acceptor<Receiver>
#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */

#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS*/

C++实战项目指南:从工程思维到面试亮点的核心路径 在软件工程领域,项目经验是衡量开发者工程化能力的关键标尺。其核心价值在于将基础技术概念转化为解决实际问题的能力。理解计算机系统原理,如内存管理、网络协议和并发模型,是构建可靠系统的基石。通过深入特定技术栈,开发者能够将理论知识应用于高性能服务、多媒体处理或嵌入式系统等具体场景,从而体现技术深度与工程思维。例如,设计一个基于Reactor模型的高并发服务器,不仅涉及网络编程,更考验对连接池、异步I/O和协议状态机等热点的综合运用。同样,在音视频开发中,熟练使用FFmpeg进行编解码与同步,能直接提升播放器项目 阅读详情

相关推荐

C++消息队列开发环境搭建:基于Asio与CMake的实战指南

消息队列作为分布式系统的核心组件,其本质是进程间通信的异步解耦机制,通过生产者-消费者模型实现数据的高效、可靠传输。在技术实现层面,高并发网络通信和高效内存管理是两大核心挑战,这要求底层框架具备强大的I/O处理能力和资源管理能力。从工程实践角度,一个模块化、可复现的开发环境是项目成功的基础,尤其对于C++这类接近系统底层的语言,构建系统和依赖管理至关重要。CMake作为现代C++项目的事实标准构建工具,配合vcpkg等包管理器,能有效解决依赖版本冲突问题,确保跨平台一致性。在库选型上,Asio提供了高效的异

cqwf95925的博客 420

ACE_POSIX_AIOCB_Proactor和ACE_WIN32_Proactor的区别

在调用流程上这两种Proactor的具体实现并无太大差异。 基本上的流程是这样的: 0.在handler的open接口中调用异步读写的例如ACE_Asynch_Read_Stream和ACE_Asynch_Write_Stream的open接口,用于绑定handler和异步完成事件。 1.调用proactor_run_event_loop来持续调用handle_events持续等待完成事件发生

chinaclock的专栏 1109

深入解析mq4cpp v1.16:C++消息中间件源码与网络编程实战

消息队列(Message Queue)作为分布式系统解耦与异步通信的核心组件,其工作原理基于生产者-消费者模型,通过消息路由、服务发现等机制实现可靠传输。在技术实现层面,高性能网络编程常采用Reactor模型配合I/O多路复用(如epoll)处理高并发连接,而协议编解码层则需解决TCP粘包/拆包问题。这些基础技术共同支撑了消息中间件在微服务、大数据处理等场景下的应用价值。本文以mq4cpp v1.16开源项目为例,通过源码剖析其**消息路由**与**服务发现**等核心模块的实现,展示如何用现代C++构建高可

weixin_34241036的博客 388

ACE通信框架的一些例子(包括MFC)

原文地址:http://blog.youkuaiyun.com/zhjb1025/article/details/4017001 被ACE折磨了几天以后整理出来的一些经验,和大家分享 一.              ace的编译安装 环境:XP,VC6.0+SP6,ACE5.4 1.    解压缩ace源代码包,假设在D:/ACE_wrappers 2.    使用vc打开D:/ACE_wrappe

Stone_Sky 2277

C++构建高性能网络安全测试工具:架构设计与核心实现

网络协议与系统编程是构建高性能安全工具的技术基石。理解TCP/IP协议栈、操作系统进程与内存管理、多线程并发等底层原理,是实现高效网络通信与资源调度的关键。这些技术通过优化I/O模型、减少数据拷贝和降低锁竞争,显著提升工具在端口扫描、协议分析等场景下的性能与稳定性。在网络安全领域,掌握这些核心能力对于开发用于授权测试与漏洞研究的模拟工具至关重要。本文以C++实现为例,深入探讨如何运用线程池、异步I/O和模糊测试框架,构建一个模块化、可扩展的网络安全测试平台,满足安全研究中对性能与可靠性的严苛要求。

weixin_34175509的博客 316

C++游戏服务器自动化测试机器人:协议驱动与高并发压力测试实战

自动化测试是保障软件质量、提升开发效率的关键工程实践,其核心原理在于通过脚本或程序模拟用户操作,自动执行测试用例并验证结果。在游戏服务器开发领域,自动化测试的技术价值尤为突出,它能够实现7x24小时不间断的回归测试、压力测试和异常场景覆盖,有效发现并发问题、逻辑漏洞和性能瓶颈。结合协议驱动和有限状态机模型,可以精准模拟真实玩家行为,构建高并发的测试负载。本文聚焦于C++游戏服务器自动化测试机器人的实现,通过集成Boost.Asio网络库和Lua脚本引擎,详细阐述了如何构建一个能够模拟真实玩家协议、执行压力测

weixin_30617737的博客 401

Linux中5种IO模型

以及。其中前四者都属于同步IO。

cmiku的博客 1361

Proactor编程模型介绍

Proactor编程模型是一种基于异步I/O的高性能事件驱动架构,适用于高并发、低延迟场景。其核心思想是通过操作系统或异步I/O库完成实际I/O操作,应用程序仅需关注业务逻辑处理。

技术人集结地 251

Linux服务器编程实践99-Proactor事件处理模式:基于异步I/O的工作流程

本文深入探讨了Linux服务器编程中的Proactor模式及其实现。Proactor模式通过异步I/O机制,将I/O操作交由内核执行,工作线程仅处理业务逻辑,实现了I/O处理与业务逻辑的完全解耦。文章详细解析了Linux的aio系列函数、Proactor工作流程和代码实现,并对比了Reactor模式,指出Proactor在高并发场景下的优势:零拷贝潜力、低线程同步开销和更好的并发支持。最后给出了内存管理、信号安全等注意事项及性能优化建议,指导开发者根据业务场景选择合适的事件处理模式。

文石_2009的博客 784

mnet:适用于 Linux 的 C++ proactor 网络库

C++03 中的终极小型 Proactor 网络库 介绍 MNet 是一个仅适用于 Linux 的小型 proactor 库。 它使用 epoll 边缘触发器来实现性能,同时通过实现一个基于 proactor 的库来保留易于使用。 MNet 库非常小,但对于大多数 Intranet 或 IPV4 TCP 任务来说已经足够了。 它仅支持带有 IPV4 的 TCP 协议。 它是一个 C++ 03 兼容库,但用户不需要使用继承来实现回调函数。 实际上 MNet 有一个内置的回调库,可以让用户使用基于签名的方式来实现回调函数。 MNet 还旨在实现高性能。 它利用带有边沿触发的 epoll 功能,并且它使用分散读取来最大程度地减少系统调用。 最后,由于边缘触发器具有特殊属性,这允许 MNet 为每个文件描述符最多调用 epoll_ctl 两次。 与 boost::asio 不同,每次事件发生时

用Python+NumPy手把手实现分数阶傅里叶变换(FRFT),搞定线性调频信号分析

本文详细介绍了如何使用Python和NumPy实现分数阶傅里叶变换(FRFT),特别针对线性调频信号(Chirp信号)分析。通过从零开始的代码实现和可视化案例,展示了FRFT在时变信号处理中的强大能力,帮助工程师和研究人员高效分析频率随时间变化的信号。

weixin_29062823的博客 218

ACE网络服务器程序开发注意事项

        最近又研究了8年前使用过的一个开源网络服务器开发框架-ACE,发现最新版本已更新到了6.4.3.因为想开发一个能运行在云端的服务器程序,所以开始按照以前的思路开始设计并编码实现。由于ACE是跨平台库,所以在VS2015下编译了ACE后,写了一个测试程序并跑在WIN7下运行。按照8年前的想法,网络服务器程序一般都是跑在Linux下的,因为性能比Windows好。但经过测试发现,起码目...

robin51201的专栏 586

腾讯云智后台开发实习面试全纪录(已offer)

腾讯云智后台开发实习面经

wenwenaier的博客 5903

tinyserver小型服务器

简介: Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器. 使用线程池 + epoll(ET和LT均实现) + 模拟Proactor模式的并发模型 使用状态机解析HTTP请求报文,支持解析GET和POST请求 通过访问服务器数据库实现web端用户注册、登录功能,可以请求服务器图片和视频文件 实现同步/异步日志系统,记录服务器运行状态 经Webbench压力测试可以实现上万的并发连接数据交换 基础测试 服务器测试环境 Ubuntu版本16.04 MySQL版本5

栋哥修炼日记 910

STM32踩坑--NoST-LINK detected

这里出现的NoST-LINK detected是没有扫描到端口 在我使用一段Fly-MCU后,有一天突然发现出现如上错误,再检查的过程中检查以下几点 1.STM32 魔术棒的设置 1.1Debug设置 1.2 utilities 设置没有问题,与原来一样又看了下端口——在设备管理器中;也没有问题 ...

qq_53002477的博客 2万+

参考线平滑-FemPosDeviation-SQP

使用SQP(顺序二次规划)对离散点进行平滑

mpt0816的博客 2439

从零实现C++轻量级Json-RPC框架:基于muduo与JsonCpp的工程实践

远程过程调用(RPC)是一种实现分布式系统间通信的核心技术,它允许程序像调用本地函数一样调用远程服务,极大地简化了网络编程的复杂性。其核心原理在于通过网络传输序列化的调用请求和响应,屏蔽了底层的通信细节。在众多RPC协议中,基于JSON格式的Json-RPC因其轻量、易读和跨语言的特性,成为构建微服务、游戏服务器和物联网应用的热门选择。本文聚焦于C++后端开发场景,针对现有框架庞大或功能简陋的痛点,通过从零构建一个轻量级Json-RPC框架的实践,深入剖析网络通信、协议设计等关键技术。我们将基于成熟稳定的m

dgqvhtlwq472235338的博客 383

代谢组数据分析(二十二):代谢组原始数据Zscore标准化和主成分分析(PCA)及热图

本教程介绍了使用Z-score标准化和主成分分析(PCA)进行代谢组学数据预处理和分析的方法。代谢物原始数据具有高噪声、高维小样本、高变异性和复杂相互作用关系等特点,因此在数据分析时需注意数据质量控制、参数选择、批次效应、假阳性控制等问题。Z-score标准化通过将数据转换为均值为0、标准差为1的标准正态分布,提高了数据的可比性,减少了系统误差,并适应了统计分析方法的需求。PCA则通过降维、去相关和特征提取,帮助理解数据的结构和模式。教程还详细介绍了数据预处理步骤,包括填补缺失值、设置名称和顺序等,并提供了

专注生信领域 2858

Unix/Linux编程:服务器模型Reactor和Proactor

网络IO,会涉及到两个系统对象,一个是用户空间调用IO的进程或者线程,另一个是内核空间的内核系统,比如发生IO操作read时,它会经历两个阶段 等待数据准备就绪 将数据从内核拷贝到进行或者线程中 因为在以上两个阶段各有不同的情况,所以出现了多种网络IO模型 服务器模型Reactor和Proactor 对高并发编程,网络连接上的消息处理,可以分为两个阶段: 等待消息准备好 消息处理 当使用默认的阻塞套接字时(例如上面提到的 1 个线程捆绑处理 1 个连接),往往是把这两个阶段合二为一,这样操作套接字的

OceanStar的博客 749

166、Sim2Real中的强化学习:域随机化与鲁棒策略

第二,训练时监控每个随机化维度对策略梯度的贡献,如果某个维度对loss的方差贡献极小,说明策略已经忽略它了,要么加大范围,要么删掉。第四,如果条件允许,用真实数据来校准随机化分布——采集真机上的传感器数据,拟合出参数分布,再把这个分布作为随机化的采样依据,这比拍脑袋定范围靠谱得多。动态随机化是很多人忽略的维度。域随机化的核心思想说白了就一句话:别去精确建模现实,而是把仿真环境本身变成一个随机分布的集合,让策略在“各种乱七八糟的物理参数”里都见过世面,这样到了真机上,不管现实落在哪个参数区间,策略都能兜住。

sundong_81的博客 27

2023全国职业技能大赛 网络系统管理 服务部署 Linux部分--基础配置

服务器和客户端基本配置如下表,各虚拟机已预装系统。一、关闭防火墙和Selinux。七、需要使用到的命令详解。三、修改root密码。

weixin_62926639的博客 999

ACE_Proactor实现

ACE_Proactor实现了Facade模式。 其方法可以分为四类。 生命周期管理方法 事件循环管理方法 定时器管理方法 IO操作facilitator方法: -须知ACE_Proactor是使用Bridge模式的。ACE_aynch_Read/Write_Stream都是使用Bridge模式来访问他们用于特定的OS平台的IO操作工厂的灵活实现。所有的ACE_Proactor实现实际都转

chinaclock的专栏 1636

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【Linux 网络编程】生动讲解 Reactor 模式与 Proactor 模式

五种 I/O 模型 先花费点时间了解这几种 I/O 模型,有助于后面的理解。 阻塞 I/O 与非阻塞 I/O 阻塞和非阻塞的概念能应用于所有的文件描述符,而不仅仅是 socket。我们称阻塞的文件描述符为阻塞 I/O,称非阻塞的文件描述符为非阻塞 I/O。 socket 在创建的时候默认是阻塞的,我们可以给 socket 系统调用的第 2 个参数传递 SOCK_NONBLOCK 标志,或者通过 fcntl 系统调用的 F_SETFL 命令将其设置为非阻塞的。 针对阻塞 I/O 执行的系统调用可能因为无法

Lafiteee的博客 737

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

操作系统-深入理解IO模型与Reactor、Proactor模式

Linux内核给每个进程都提供了一个独立的虚拟空间,并且这个地址空间是连续的,进程就可以通过这个地址空间很方便地访问虚拟内存。 用户进程所能访问到的地址空间被称为用户空间,而被Linux内核系统调用或使用的地址被称为内核空间。

BoringError的博客 1132
上一篇: struct_config.xml中action/set-property标签的用法
下一篇: pragma pack对template结构的作用在VC7与gcc中差别
larrin
博客等级 码龄23年 2粉丝 45原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值