[linux,c++]使用指针函数实现多个函数调用_Advanced

本文介绍了如何在Linux环境中,使用C++通过指针函数实现服务器端的多函数调用,模拟TCP服务器接受并处理来自多个用户请求的过程。程序创建一个监听进程(TCPListener),监听特定端口的请求,接收到请求后,创建新的子进程(Agent)处理请求。通过指针函数,可以根据进程类型调用不同的处理方法,减少了代码冗余。虽然不涉及具体的网络通信实现,但强调了指针函数在简化代码结构中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这段程序的中心思想是:想要模拟在网络通信中的服务器端接受来自多个用户的请求,

服务器是通过创建一个TCPListener的进程(线程),来接受来自多个用户发送的请求事件(events)或是连接。

我们知道服务器是作为运行在主机上的一个进程,该进程中的某些方法为其他程序或是用户提供服务,

那么其他程序或是用户是如何找到这个提供服务的程序的呢? 答案是通过端口号来唯一锁定该服务器,

如果涉及到远程访问的话,还需要涉及到主机号+端口号来锁定唯一的服务器,即请求者通过向该端口号发送请求消息,使得消息被服务器端接收到。


在服务器(进程)被创建后,它会创建一个 监听进程(该监听进程的声明周期与服务器的声明周期是相同的),

这个监听进程用来监听唯一指定服务器端的端口上面是否有请求者发来请求消息,如果有请求消息,

则该监听进程并不亲自执行这个消息, 而是创建一个新的子进程(线程)然后将这个请求消息分配给新创建的子进程(线程),

等到子进程(线程)在调用服务器端上的某些资源和方法执行请求得到结果之后,会将结果返回给监听进程,

监听进程再根据请求者的地址信息,将结果发送至请求者。


当然,上面所述的仅仅是最简单的一种实现思想,在大多数的服务器接收请求信息的时候,采用的是线程来作为调度单元的,

并且基于的模型也更加的复杂,如果需要对客户的请求响应时间并不很高的话,通常在服务器端会开辟一个响应时间的队列,

这个队列将作为一个用于临时存放事件的缓冲区,如果请求到来而服务器端的进程来不及响应,那么将其存放至队列中,带到

服务器端的监听进程(通常也成为是分配者)会从队列中(队头)取出一个事件,将其分配给一个代理(Agent)让其执行该事件的。


<不过在本段代码中,为了突出指针函数的使用方法,并不涉及任何的网络传输信息的实现,并且也并不涉及进程的创建与调用>


而在下面的程序中, TCPListener 所扮演的就是监听进程,而Agent 代理进程扮演的就是上述过程中的子进程。

当然,这篇文章的主要目的是讲解TCPListener和Agent所执行的方法是两种完全不同的方法,但是却有着相同的方法返回值,和参数。

正因如此,才可以创建一个公共的指针函数,使得在程序使用的过程中,只需要传入此次运行的进程类型值,即可返回特定方法(listener / agent)

然后通过指针函数指向该函数所返回的特定方法指针,从而实现最大程度的减少代码的书写。


//g++ -o funcEntry  funcEntry.hpp funcEntry.cpp 


#include <map>

#ifndef FUNCENTRY_HPP__
#define FUNCENTRY_HPP__

/**
define different message type,
MSG_COMMAND is used by tcp listener
MSG_DATA can only be used by agent 
*/
enum MSG_TYPE
{
  MSG_COMMAND = 0 ,
  MSG_DATA,
  UNKNOWN_MSG_TYPE
} ;

/**
define different process : 
TCPLISTENER_PROCESS the listener,
created by the server to create agent process and allocate
requests to them 
AGENT_PROCESS the agent ,
created by the tcp listener ,allocated tasks or requests by listener
*/

enum PROCESS_TYPE
{
  TCPLISTENER_PROCESS = 0,
  AGENT_PROCESS,
  UNKNOWN_PROCESS_TYPE
} ;

/**
message 's struct ,
MSG_TYPE is the type of the message( command or data )
char *_data is the content of the message
*/

struct msg
{
  MSG_TYPE _type;
  char*    _data ;
  msg (MSG_TYPE type , char *data) :_type (type),_data(data)
  {}
} ;

typedef msg message ;
typedef int (*funcEntryPoint) (message *_msg ) ;
//here we define the pointer function which is also be called the function entry 
//you know pointer is used to describe as the address with the same meaning of function entry


struct proEntryPointInfo
{
  PROCESS_TYPE   _type ;
  int            _regiStatus ;
  funcEntryPoint _entryPoint ;
} ;


//here are the two functions will be pointed by the pointer function
int TCPListenerEntryPoint   ( message *_msg ) ;
int AgentExecutorEntryPoint ( message *_msg ) ;

int registerProcessType     ( PROCESS_TYPE type , const char *name) ;
const char * getProcessNameByType ( PROCESS_TYPE type  ) ;

/**
Parameter : PROCESS_TYPE type the type of the processor 
return  :  funcEntryPoint return different function entry points refering 
to different type values
type = TCPLISTENER_PROCESS : return TCPListenerEntryPoint entry point
type = AGENT_PROCESS : 	     return AgentExecuteEntryPoint entry point
type = otherwise     :       return NULL  
*/
funcEntryPoint getProcessorEntryPoint ( PROCESS_TYPE type ) ;

#endif




#include "funcEntry.hpp"

using namespace std ;

static map<PROCESS_TYPE ,string> proTypeNameMap ;

int registerProcessType ( PROCESS_TYPE type , const char *name )
{
    map<PROCESS_TYPE,string>::iterator it = proTypeNameMap.find(type) ;

    if ( it != proTypeNameMap.end() )
    {
        cout<<"names confliction "<<type<<" alread exists "<<endl ;
        return -1 ;
    }

    proTypeNameMap[type] = string(name) ;
//    cout<<"length of list "<<proTypeNameMap.size() <<endl ;
    return 0 ;
}

const char * getProcessNameByType ( PROCESS_TYPE type )
{
    map<PROCESS_TYPE,string>::iterator it = proTypeNameMap.find(type) ;

    if ( it == proTypeNameMap.end() )
    {
      return "Unknow_Type" ;
    }
    return it->second.c_str() ;

}

#define CREATE_PROCESS_ENTRY_POINT(type,name,entryFunc) \
{type, registerProcessType(type,name),entryFunc}

int TCPListenerEntryPoint ( message *_msg )
{
  if ( _msg->_type == MSG_COMMAND )
  {
   cout<<"TCPListener receive command message \n content:"<<endl ;
   cout<<_msg->_data<<endl ;
   return 0 ;
  }
  else
  {
   cout<<"TCPListener received error message type "<<endl ;
   cout<<"TCPListener receives only command type messages"<<endl ;
   return -1 ;
  }
}

int AgentExecutorEntryPoint ( message *_msg )
{
  if ( _msg->_type == MSG_DATA )
  {
     cout<<"Agent Executor receive data message \n content : "<<endl ;
     cout<<_msg->_data<<endl ;
     return 0 ;
  }
  else
  {
     cout<<"agent received error message type "<<endl ;
     cout<<"agent only receives data type messages "<<endl ;
     return -1;
  }
}


funcEntryPoint getProcessEntryPoint ( PROCESS_TYPE type )
{
  static proEntryPointInfo _entryFuncList [] = {

  CREATE_PROCESS_ENTRY_POINT
  (TCPLISTENER_PROCESS,"TCPListener",TCPListenerEntryPoint) ,

  CREATE_PROCESS_ENTRY_POINT
  (AGENT_PROCESS,"AgentExecutor" ,AgentExecutorEntryPoint) ,

  CREATE_PROCESS_ENTRY_POINT
  (UNKNOWN_PROCESS_TYPE,"UnknowProcess",NULL)
  } ;

  static unsigned int _entryNum = sizeof( _entryFuncList ) /
                                  sizeof( proEntryPointInfo) ;

 unsigned int _targetIndex = _entryNum -1 ;

 for ( unsigned int i = 0 ; i < _entryNum ; i++ )
 {
     if ( type == _entryFuncList[i]._type )
     {
        _targetIndex = i ;
        break ;
     }
 }

 return _entryFuncList[_targetIndex]._entryPoint ;
}

void close ()
{
  map<PROCESS_TYPE ,string>::iterator it = proTypeNameMap.begin() ;


  proTypeNameMap.erase(it , proTypeNameMap.end () ) ;
  return ;
}



int main ( int argc , char *argv[] )
{
 // registerProcessType (TCPLISTENER_PROCESS, "TcpListener") ;
//  registerProcessType (AGENT_PROCESS, "AgentExecutor") ;

  funcEntryPoint myFuncEntry ;
  message *msgCommand ,*msgData ;

  msgCommand = new message( MSG_COMMAND , "disconnect DB") ;
  msgData    = new message( MSG_DATA ,  "hello,table size is 100 bytes" ) ; ;

  cout<<"we first ask for the agent entry point"<<endl ;
  myFuncEntry =  getProcessEntryPoint (AGENT_PROCESS) ;
  cout<<endl ;

  cout<<"use agent entry point , send command message "<<endl ;
  myFuncEntry(msgCommand) ;
  cout<<endl ;

  cout<<"use agent entry point, send data message "<<endl ;
  myFuncEntry(msgData) ;
  cout<<endl ;

  cout<<"we ask for the TCP listener entry point "<<endl ;
  myFuncEntry = getProcessEntryPoint (TCPLISTENER_PROCESS) ;
  cout<<endl ;

  cout<<"use tcp listener entry point , send command message"<<endl ;
  myFuncEntry(msgCommand) ;
  cout<<endl ;

  cout<<"use tcp listener entry point , send data message "<<endl ;
  myFuncEntry(msgData) ;

 //cout<<getProcessNameByType(TCPLISTENER_PROCESS) <<endl ;
 //cout<<getProcessNameByType(AGENT_PROCESS) <<endl ;   

 // getProcessEntryPoint( AGENT_PROCESS ) ;

  close() ;
  delete msgData ;
  delete msgCommand ;

  return 0 ;
}
                           


//next section we will add some network communication methods in unix/ linux libraries  , and it will be a little more complex 


//coding me

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值