这段程序的中心思想是:想要模拟在网络通信中的服务器端接受来自多个用户的请求,
服务器是通过创建一个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