基于请求代理的中间件模型
2008-09-03 09:59
141 查看
对象请求代理体系结构是一种崭新的技术,它以CORBA为代表。在这里,我们实现了一个基于请求代理体系结构的简单模型,藉此说明中间件的工作原理。
系统由三个模块组成:客户端、服务器和代理。即Client,Server和Agent。实现方法是使用Winsock编程技术(有关Winsock编程的技术可以参考相关文献),编程环境是VC++6.0。
首先作如下定义:
#define DataLength 80 file://定义数据长度
#define AgentPort 14000//定义代理的端口号
#define DefaultClientPort 12000//定义客户端的端口号
#define DefaultServerPort 13000//定义服务器的端口号
系统工作原理如下是:客户端、服务器和代理各有一个独立的IP地址和端口号(IP地址和端口号的组合可以确定客户端程序、服务程序和代理服务器的通信地址)。我们要实现的是客户端和服务器之间的信息交互,但是现在面临这样的问题:客户端和服务器的地址以及端口都是可变的,它们并不固定,因此在信息交互之前,客户端无法知道服务器的地址,服务器也并不知道客户端的地址。唯一确定的是代理服务器程序的IP地址和端口号,它是不变的。
系统实现的方式如下:客户端启动时首先向代理服务器注册自己的信息,主要是自己的IP地址和端口号,如果此时服务器已经注册,则代理服务器将服务器的地址信息传递给客户端,否则客户端等待。(系统工作原理如下图所示)
服务器启动时也首先向代理服务器注册自己的信息,如果此时客户端已经注册,则代理服务器将客户端的地址信息传递给服务器(很多情况下并不需要这样的操作,因为总是客户端向服务器发送请求服务的信号)。
客户端得到服务器的地址信息之后,就可以直接和服务器进行交互,这样,代理服务器就可以退出系统,甚至关掉。这是在CORBA中比较典型的一种代理方式。
在另外一种情况下:如果希望服务器能够在不影响客户端程序的前提下随时扩展,那么可以要求客户端程序在发送服务请求时,直接发给代理服务器,然后由代理服务器进行一定的权限审查,然后转发给服务器。服务器返回的结果也由代理服务器转发给客户端。这是目前常见的WWW代理服务器的一般工作方式。在这样的情况下,本例也是可以适应的,只要在程序中加以限制即可。
本例的关键代码如下:
代理服务器:
初始化处理:
BOOL CAgent_ZhyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
COleVariant LocalPort,LocalIPAddress;
LocalPort.vt=VT_I2;
LocalPort.intVal=AgentPort;
LocalIPAddress.vt=VT_BSTR;
file://LocalIPAddress.bstrVal=SysAllocString(L"90.0.0.111");
LocalIPAddress=m_ReceiveSocket.GetLocalIP();
m_ReceiveSocket.SetProtocol(1);
m_ReceiveSocket.Bind(LocalPort,LocalIPAddress);
Socket_ID=m_ReceiveSocket.GetSocketHandle();
if(Socket_ID==INVALID_SOCKET)
{
AfxMessageBox("Invalid socket!");
}
LocalHostName=m_ReceiveSocket.GetLocalHostName();
HasGotServerAddress=FALSE;
HasGotClientAddress=FALSE;
ServerIPAddressAsString="";
ClientIPAddressAsstring="";
ServerPortAsstring="";
ClientPortAsstring="";
return TRUE; // return TRUE unless you set the focus to a control
}
接收到数据报(使用UDP协议):
void CAgent_ZhyDlg::OnDataArrivalWinsock1(long bytesTotal)
{
if (!HasStopped)
{
// TODO: Add your control notification handler code here
char FAR * buf;int length; char SourceAddress[20];
Socket_ID=m_ReceiveSocket.GetSocketHandle();
buf=( char FAR *)malloc(80);
sockaddr_in srcsockaddr,tempsock;
length=sizeof(sockaddr);
int ReceivedNumber=recvfrom(Socket_ID,(char *)buf,80,0,(sockaddr *)&srcsockaddr,&length);
if (ReceivedNumber>=1)
{
buf[ReceivedNumber]=0;
}
memcpy((void *)&tempsock,(void *)&srcsockaddr,sizeof(sockaddr));
length=sizeof(sockaddr);
strcpy(SourceAddress,inet_ntoa(tempsock.sin_addr));
CString SourcePortAsstring,BytesTotalAsString;
SourcePortAsstring.Format("%d",ntohs(tempsock.sin_port));
BytesTotalAsString.Format("%d",bytesTotal);
if (ntohs(tempsock.sin_port)==DefaultClientPort) file://Client information
{
HasGotClientAddress=TRUE;
ClientPortAsstring=SourcePortAsstring;
ClientIPAddressAsstring=SourceAddress;
}//数据包源地址之端口号和客户端缺省端口相符,取得客户端地址
if (ntohs(tempsock.sin_port)==DefaultServerPort) // Server information
{
HasGotServerAddress=TRUE;
ServerPortAsstring=SourcePortAsstring;
ServerIPAddressAsString=SourceAddress;
}//数据包源地址之端口号和服务器缺省端口相符,取得服务器端地址
m_Edit=m_Edit+"Message from : "+SourceAddress+" Port: "+SourcePortAsstring+" BytesTotal : "+BytesTotalAsString+"/r/n"+"Message : "+buf+"/r/n/r/n";//将收到的信息显示出来。
free(buf);
UpdateData(FALSE);
}
}
将客户端地址发送给服务器:
void CAgent_ZhyDlg::OnBUTTONSendToServer()
{
// TODO: Add your control notification handler code here
file://send client information to server
if (HasGotClientAddress)
{
if (HasGotServerAddress)
{
Socket_ID=m_ReceiveSocket.GetSocketHandle();
if(Socket_ID==INVALID_SOCKET)
{
AfxMessageBox("Illegal Socket ID");
closesocket(Socket_ID);
}
LPHOSTENT hp;
hp=gethostbyname(LocalHostName);
if(hp==0)
{
AfxMessageBox("Illegal agent name");
closesocket(Socket_ID);
}
SOCKADDR_IN m_sockAddr,DestinationAddress;
memcpy(&m_sockAddr.sin_addr,(char FAR*)hp->h_addr,hp->h_length);
char FAR * Send_Buffer;
int bufferLength;
Send_Buffer=( char FAR *)malloc(100);
strcpy(Send_Buffer,"ClientIP: "+ClientIPAddressAsstring+"/r/nClientPort: "+ClientPortAsstring);
bufferLength=strlen(Send_Buffer);
m_sockAddr.sin_family=AF_INET;
m_sockAddr.sin_port=htons(AgentPort);
DestinationAddress.sin_addr.S_un.S_addr=inet_addr(ServerIPAddressAsString);
DestinationAddress.sin_family=AF_INET;
DestinationAddress.sin_port=htons(DefaultServerPort);
sendto(Socket_ID,Send_Buffer,bufferLength,0,
(struct sockaddr FAR *)&DestinationAddress,
sizeof(DestinationAddress));
file://发送到目标地址
AfxMessageBox("Information of client's IP address & port available,/r/n successfully sent to server!");
}else {
AfxMessageBox("None information of server's IP address & port available,/r/n Can not send client information!");}
}else {AfxMessageBox("None information of client's IP address & port available,/r/n Can not send to server!");}
}
将服务器地址发送给客户端:
void CAgent_ZhyDlg::OnBUTTONSendToClient()
{
// TODO: Add your control notification handler code here
file://send server infomation to client
if (HasGotServerAddress)
{
if (HasGotClientAddress)
{
Socket_ID=m_ReceiveSocket.GetSocketHandle();
if(Socket_ID==INVALID_SOCKET)
{
AfxMessageBox("Illegal Socket ID");
closesocket(Socket_ID); }
LPHOSTENT hp;
hp=gethostbyname(LocalHostName);
if(hp==0)
{
AfxMessageBox("Illegal agent name");
closesocket(Socket_ID);
}
SOCKADDR_IN m_sockAddr,DestinationAddress;
memcpy(&m_sockAddr.sin_addr,(char FAR*)hp->h_addr,hp->h_length);
char FAR * Send_Buffer;
int bufferLength;
Send_Buffer=( char FAR *)malloc(100);
strcpy(Send_Buffer,"ServerIP: "+ServerIPAddressAsString+"/r/nServerPort: "+ServerPortAsstring);
bufferLength=strlen(Send_Buffer);
m_sockAddr.sin_family=AF_INET;
m_sockAddr.sin_port=htons(AgentPort);
DestinationAddress.sin_addr.S_un.S_addr=inet_addr(ClientIPAddressAsstring);
DestinationAddress.sin_family=AF_INET;
DestinationAddress.sin_port=htons(DefaultClientPort);
sendto(Socket_ID,Send_Buffer,bufferLength,0,
(struct sockaddr FAR *)&DestinationAddress,
sizeof(DestinationAddress)); file://send server's ip & port information to client
AfxMessageBox("Information of server's IP address & port available,/r/n successfully sent to client!");
}else {
AfxMessageBox("None information of client's IP address & port available,/r/n Can not send server information!");}
}else {
AfxMessageBox("None information of server's IP address & port available,/r/n Can not send to client!");}
}
以上是代理服务器的一些关键代码,这些代码已经经过调试通过,感兴趣的朋友可以直接使用。另外客户端和服务器端的处理方式和代理服务器类似,不过稍微简化一些。可以参考代理服务器的代码实现客户端和服务器的代码,在此不作赘述。
以上实现的就是目前比较先进的请求-代理体系结构的基本模型,它是一种基于ORB的中间件模型。采用的实现手段是基于Winsock的网络编程技术。当然这仅仅是一个简单的模型,它远远没有达到实用化的程度。然而重要的不是实现,而是这种思想。大家只要了解和把握了这种思想,也就掌握了中间件技术的基本思想。
系统由三个模块组成:客户端、服务器和代理。即Client,Server和Agent。实现方法是使用Winsock编程技术(有关Winsock编程的技术可以参考相关文献),编程环境是VC++6.0。
首先作如下定义:
#define DataLength 80 file://定义数据长度
#define AgentPort 14000//定义代理的端口号
#define DefaultClientPort 12000//定义客户端的端口号
#define DefaultServerPort 13000//定义服务器的端口号
系统工作原理如下是:客户端、服务器和代理各有一个独立的IP地址和端口号(IP地址和端口号的组合可以确定客户端程序、服务程序和代理服务器的通信地址)。我们要实现的是客户端和服务器之间的信息交互,但是现在面临这样的问题:客户端和服务器的地址以及端口都是可变的,它们并不固定,因此在信息交互之前,客户端无法知道服务器的地址,服务器也并不知道客户端的地址。唯一确定的是代理服务器程序的IP地址和端口号,它是不变的。
系统实现的方式如下:客户端启动时首先向代理服务器注册自己的信息,主要是自己的IP地址和端口号,如果此时服务器已经注册,则代理服务器将服务器的地址信息传递给客户端,否则客户端等待。(系统工作原理如下图所示)
服务器启动时也首先向代理服务器注册自己的信息,如果此时客户端已经注册,则代理服务器将客户端的地址信息传递给服务器(很多情况下并不需要这样的操作,因为总是客户端向服务器发送请求服务的信号)。
客户端得到服务器的地址信息之后,就可以直接和服务器进行交互,这样,代理服务器就可以退出系统,甚至关掉。这是在CORBA中比较典型的一种代理方式。
在另外一种情况下:如果希望服务器能够在不影响客户端程序的前提下随时扩展,那么可以要求客户端程序在发送服务请求时,直接发给代理服务器,然后由代理服务器进行一定的权限审查,然后转发给服务器。服务器返回的结果也由代理服务器转发给客户端。这是目前常见的WWW代理服务器的一般工作方式。在这样的情况下,本例也是可以适应的,只要在程序中加以限制即可。
本例的关键代码如下:
代理服务器:
初始化处理:
BOOL CAgent_ZhyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
COleVariant LocalPort,LocalIPAddress;
LocalPort.vt=VT_I2;
LocalPort.intVal=AgentPort;
LocalIPAddress.vt=VT_BSTR;
file://LocalIPAddress.bstrVal=SysAllocString(L"90.0.0.111");
LocalIPAddress=m_ReceiveSocket.GetLocalIP();
m_ReceiveSocket.SetProtocol(1);
m_ReceiveSocket.Bind(LocalPort,LocalIPAddress);
Socket_ID=m_ReceiveSocket.GetSocketHandle();
if(Socket_ID==INVALID_SOCKET)
{
AfxMessageBox("Invalid socket!");
}
LocalHostName=m_ReceiveSocket.GetLocalHostName();
HasGotServerAddress=FALSE;
HasGotClientAddress=FALSE;
ServerIPAddressAsString="";
ClientIPAddressAsstring="";
ServerPortAsstring="";
ClientPortAsstring="";
return TRUE; // return TRUE unless you set the focus to a control
}
接收到数据报(使用UDP协议):
void CAgent_ZhyDlg::OnDataArrivalWinsock1(long bytesTotal)
{
if (!HasStopped)
{
// TODO: Add your control notification handler code here
char FAR * buf;int length; char SourceAddress[20];
Socket_ID=m_ReceiveSocket.GetSocketHandle();
buf=( char FAR *)malloc(80);
sockaddr_in srcsockaddr,tempsock;
length=sizeof(sockaddr);
int ReceivedNumber=recvfrom(Socket_ID,(char *)buf,80,0,(sockaddr *)&srcsockaddr,&length);
if (ReceivedNumber>=1)
{
buf[ReceivedNumber]=0;
}
memcpy((void *)&tempsock,(void *)&srcsockaddr,sizeof(sockaddr));
length=sizeof(sockaddr);
strcpy(SourceAddress,inet_ntoa(tempsock.sin_addr));
CString SourcePortAsstring,BytesTotalAsString;
SourcePortAsstring.Format("%d",ntohs(tempsock.sin_port));
BytesTotalAsString.Format("%d",bytesTotal);
if (ntohs(tempsock.sin_port)==DefaultClientPort) file://Client information
{
HasGotClientAddress=TRUE;
ClientPortAsstring=SourcePortAsstring;
ClientIPAddressAsstring=SourceAddress;
}//数据包源地址之端口号和客户端缺省端口相符,取得客户端地址
if (ntohs(tempsock.sin_port)==DefaultServerPort) // Server information
{
HasGotServerAddress=TRUE;
ServerPortAsstring=SourcePortAsstring;
ServerIPAddressAsString=SourceAddress;
}//数据包源地址之端口号和服务器缺省端口相符,取得服务器端地址
m_Edit=m_Edit+"Message from : "+SourceAddress+" Port: "+SourcePortAsstring+" BytesTotal : "+BytesTotalAsString+"/r/n"+"Message : "+buf+"/r/n/r/n";//将收到的信息显示出来。
free(buf);
UpdateData(FALSE);
}
}
将客户端地址发送给服务器:
void CAgent_ZhyDlg::OnBUTTONSendToServer()
{
// TODO: Add your control notification handler code here
file://send client information to server
if (HasGotClientAddress)
{
if (HasGotServerAddress)
{
Socket_ID=m_ReceiveSocket.GetSocketHandle();
if(Socket_ID==INVALID_SOCKET)
{
AfxMessageBox("Illegal Socket ID");
closesocket(Socket_ID);
}
LPHOSTENT hp;
hp=gethostbyname(LocalHostName);
if(hp==0)
{
AfxMessageBox("Illegal agent name");
closesocket(Socket_ID);
}
SOCKADDR_IN m_sockAddr,DestinationAddress;
memcpy(&m_sockAddr.sin_addr,(char FAR*)hp->h_addr,hp->h_length);
char FAR * Send_Buffer;
int bufferLength;
Send_Buffer=( char FAR *)malloc(100);
strcpy(Send_Buffer,"ClientIP: "+ClientIPAddressAsstring+"/r/nClientPort: "+ClientPortAsstring);
bufferLength=strlen(Send_Buffer);
m_sockAddr.sin_family=AF_INET;
m_sockAddr.sin_port=htons(AgentPort);
DestinationAddress.sin_addr.S_un.S_addr=inet_addr(ServerIPAddressAsString);
DestinationAddress.sin_family=AF_INET;
DestinationAddress.sin_port=htons(DefaultServerPort);
sendto(Socket_ID,Send_Buffer,bufferLength,0,
(struct sockaddr FAR *)&DestinationAddress,
sizeof(DestinationAddress));
file://发送到目标地址
AfxMessageBox("Information of client's IP address & port available,/r/n successfully sent to server!");
}else {
AfxMessageBox("None information of server's IP address & port available,/r/n Can not send client information!");}
}else {AfxMessageBox("None information of client's IP address & port available,/r/n Can not send to server!");}
}
将服务器地址发送给客户端:
void CAgent_ZhyDlg::OnBUTTONSendToClient()
{
// TODO: Add your control notification handler code here
file://send server infomation to client
if (HasGotServerAddress)
{
if (HasGotClientAddress)
{
Socket_ID=m_ReceiveSocket.GetSocketHandle();
if(Socket_ID==INVALID_SOCKET)
{
AfxMessageBox("Illegal Socket ID");
closesocket(Socket_ID); }
LPHOSTENT hp;
hp=gethostbyname(LocalHostName);
if(hp==0)
{
AfxMessageBox("Illegal agent name");
closesocket(Socket_ID);
}
SOCKADDR_IN m_sockAddr,DestinationAddress;
memcpy(&m_sockAddr.sin_addr,(char FAR*)hp->h_addr,hp->h_length);
char FAR * Send_Buffer;
int bufferLength;
Send_Buffer=( char FAR *)malloc(100);
strcpy(Send_Buffer,"ServerIP: "+ServerIPAddressAsString+"/r/nServerPort: "+ServerPortAsstring);
bufferLength=strlen(Send_Buffer);
m_sockAddr.sin_family=AF_INET;
m_sockAddr.sin_port=htons(AgentPort);
DestinationAddress.sin_addr.S_un.S_addr=inet_addr(ClientIPAddressAsstring);
DestinationAddress.sin_family=AF_INET;
DestinationAddress.sin_port=htons(DefaultClientPort);
sendto(Socket_ID,Send_Buffer,bufferLength,0,
(struct sockaddr FAR *)&DestinationAddress,
sizeof(DestinationAddress)); file://send server's ip & port information to client
AfxMessageBox("Information of server's IP address & port available,/r/n successfully sent to client!");
}else {
AfxMessageBox("None information of client's IP address & port available,/r/n Can not send server information!");}
}else {
AfxMessageBox("None information of server's IP address & port available,/r/n Can not send to client!");}
}
以上是代理服务器的一些关键代码,这些代码已经经过调试通过,感兴趣的朋友可以直接使用。另外客户端和服务器端的处理方式和代理服务器类似,不过稍微简化一些。可以参考代理服务器的代码实现客户端和服务器的代码,在此不作赘述。
以上实现的就是目前比较先进的请求-代理体系结构的基本模型,它是一种基于ORB的中间件模型。采用的实现手段是基于Winsock的网络编程技术。当然这仅仅是一个简单的模型,它远远没有达到实用化的程度。然而重要的不是实现,而是这种思想。大家只要了解和把握了这种思想,也就掌握了中间件技术的基本思想。
相关文章推荐
- 基于jdk5.0下的URl代理请求
- Xianfeng轻量级Java中间件平台:基于RBAC模型实现权限控制的原理
- Xianfeng轻量级Java中间件平台:基于RBAC模型实现权限控制的原理
- 基于信赖域的动态径向基函数代理模型优化策略
- 基于中间件的查询优化模型
- 基于管道化和事件驱动模型的Web请求处理(一)
- 详解基于angular-cli配置代理解决跨域请求问题
- 基于管道化和事件驱动模型的Web请求处理(一)
- 基于动态径向基函数(DRBF)代理模型的优化策略
- 基于管道化和事件驱动模型的Web请求处理(二)
- 在基于vue的webpack脚手架开发中使用了代理转发,结果浏览器发出的请求中不带cookie导致登录时总是session失效怎么办?
- 基于angular-cli配置代理解决跨域请求问题
- 分布式Web应用----基于Socket+动态代理实现简单RPC 生产者消费者模型
- 基于管道化和事件驱动模型的Web请求处理(二)
- 基于管道化和事件驱动模型的Web请求处理(二)
- 基于管道化和事件驱动模型的Web请求处理(一)
- Scrapy 扩展中间件: 针对特定响应状态码,使用代理重新请求
- 基于管道化和事件驱动模型的Web请求处理(一)
- 【2016美团】浏览器和服务器在基于https进行请求链接到数据传输过程中,用到了如下哪些技术
- Android基于Socket无线遥控(1)--Socket基本模型搭建