企业安全策略下的跨平台数据同步
作者:耿昌宇1,朱允文2,洪建东2,居悌1发布时间:2001/05/28
文章摘要:
本文探讨了跨平台数据同步的方法,并举例说明了在企业安全策略下实现跨平台数据同步在设计Intranet自动化工具中的应用。
关键词:企业安全策略、Intranet自动化工具、Socket通信、组件化编程
正文:
企业安全策略下的跨平台数据同步
1 引言
关于B-S开发模式的好处已经被讨论了很多,Intranet自动化工具在现代企业办公自动化中的应用正日益普及。
随着现代企业朝着国际化、集团化的方向发展,现代企业内部各部门之间出现了分工细密化和分布全球化的趋势。分工细密化和分布全球化的趋势使得各部门之间难以找到一个较完整的可共享的数据和可适用于各部门间独立管理的工具,各部门在开发自己的Intranet自动化工具的时候会根据本部门的特点和资源条件选择自己的Intranet发布平台。一方面,部门原有的数据发布平台在一定程度上影响了部门对Intranet发布平台的选择;另一方面,在选定了自己的Intranet发布平台的同时,原来与其他部门共享数据的部门也相应地选择了自己的数据发布平台。
同时,现代企业内部各部门之间的协同工作也越来越密切,不同部门之间通常需要访问的数据能同步更新,或者至少能在一定的时间间隔内进行数据同步。虽然大部分的数据库产品都有自己的基于TCP/IP的访问方式,但在企业安全的策略下,各部门通常会更改对IP端口的访问方式的配置,并开发出自己的内部数据访问工具;有的部门即使使用了数据库产品的默认设置,也很少公开数据库访问的用户名和密码。因此,在各部门之间通过数据库客户端访问工具进行直接的跨平台数据访问与同步几乎不具备可行性。
本文是笔者在摩托罗拉中国软件中心实习期间参与开发Intranet自动化工具的设计开发过程中面临的数据同步问题解决方案的总结。
2 几种跨平台数据同步方案
在介绍常用跨平台数据同步方法之前有必要简要介绍一下所开发的Intranet自动化工具的设计目的和状况。
所开发的Intranet自动化工具是运行在Windows NT平台上的ASP应用程序,其设计目的是将本地Windows NT平台上的CR Tracking(Change Request Tracking, 变更需求跟踪)Access数据库与美国UNIX平台上含有CR Tracking信息的Rational ClearDDTS(Distributed Defects Tracking System, 分布式错误跟踪系统。以下简称DDTS)数据库进行同步更新,以实现CR信息的本地Web访问和跟踪。在数据同步过程中要求实现的功能包括:获取DDTS数据库中的新数据用于Access数据库的添加、获取DDTS数据库中指定纪录的字段值用于Access数据库的更新。
在接手进一步开发Intranet自动化工具之前,该项目组已经有了一个CR Tracking的Intranet工具,使用该工具可以进行CR的输入、修改、查询和列表统计。该Intranet工具要求与CR相关的人员主动使用DDTS工具查询相关CR的信息,并将信息在Web录入页面上输入到Web服务器上的本地数据库,供CR Tracking使用。
这种Intranet工具使用的数据同步方法是利用DDTS数据访问工具,手工数据同步。该数据同步的方法实现简单,但操作繁琐,特别是在查询时需要重复性地输入类似的SQL语句,使得这项工作显得枯燥无味。从严格意义上讲,这不能算是一种跨平台数据同步的解决方案。
考虑到大部分的数据库产品都有自己的基于TCP/IP的访问方式,要求相关部门开放数据库的IP端口访问及受限的用户名和密码给Intranet开发人员也许是一个简单的实现跨平台数据同步的方法。使用这种方法,只需在Windows NT Web服务器中安装相应的ODBC驱动程序,然后在设计ASP程序时使用ADO编程,进行数据的简单查询和添加、修改即可进行跨平台数据同步,设计十分简单。但这种方法存在两方面的问题:一是在开放数据库IP端口访问的用户名和密码的同时,即给该数据库所在部门带来了安全隐患,一旦Web服务器受到攻击而使用户名和密码被窃取,开放的数据库也就处在被攻击的风险之中;二是有的部门使用的是第三方开发的基于数据库的工具(如DDTS工具),其部门本身并没有数据库的管理权限,因而也就无法添加用户名和分配权限。
在开发过程中,采用基于Socket通信的跨平台数据同步方法。
3 一种基于Socket通信的跨平台数据同步方法
基于Socket通信的跨平台数据同步方法采用客户机/服务器的概念,在分属于不同部门的不同平台的计算机上分别开发负责侦听的Socket服务器和负责连接的Socket客户端。以获取DDTS数据库中指定纪录的字段值为例,当客户端和服务器连接成功时,客户端向服务器发送相关CR的关键字以及需要获取的字段名,服务器通过调用DDTS工具的相应命令来获得客户端所需要的字段数据并发送给客户端。
这里,Socket服务器运行在DDTS所在的美国UNIX主机上,采用多进程编程。其中实现Socket侦听、连接与数据传输部分的关键代码如下(以获取DDTS数据库中指定纪录的字段值为例):
void fireman() /* 清除僵死进程 */
{
signal(SIGCHLD,fireman);
while (waitpid(-1, NULL, WNOHANG) > 0)
;
}
int main()
{
/*
……
变量声明、初始化
*/
signal(SIGCHLD,fireman); /* 指定信号处理句柄以清除僵死进程 */
if ((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
return printf("Can not open TCP SOCKET!\n");
bzero((char *)&serv_addr,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_addr.sin_port=htons(portnum); /* 指定端口号 */
if (bind(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0)
return printf("Bind SOCKET error!\n");
listen(sockfd,5);
for(; ;)
{
if ((newsockfd=accept(sockfd)) < 0) /* 建立连接 */
{
if (errno == EINTR) /* EINTR might happen on accept(), */
continue; /* try again */
return printf("Can not accept newsocket\n"); /* bad */
exit(1);
}
if ((childpid=fork())==0)
{
close(sockfd);
socketopen = 1;
while(socketopen == 1){
Readn(newsockfd,buf,10);
buf[10] = 0;
strcpy(cr_no,buf);
Writen(newsockfd,"OK",2);
Readn(newsockfd,buf,3);
buffer[3] = 0;
len = atoi(buf);
Writen(newsockfd,"OK",2);
Readn(newsockfd,buf,len);
buf[len] = 0;
strcpy(field_name,buf); /* 获取Socket请求数据 */
strcpy(cmd,HOME);
strcat(cmd,"Get_DDTS_Field defects ");
strcat(cmd,cr_no);
strcat(cmd," ");
strcat(cmd,field_name);
ptr = popen(cmd,"r"); /* 运行查询脚本 */
memset(buf,0,BUFSIZ);
i = fread(buf,BUFSIZ,1,ptr);
if (strlen(buf) == 0)
strcpy(buf,"Not Exist! ");
Writen(newsockfd,buf,strlen(buf)-1);/* 发送查询结果 */
pclose(ptr);
}
exit(0);
}
else
close(newsockfd);
continue;
}
}
代码中,对建立连接是产生的EINTR错误的处理和对SIGCHLD信号的处理是关键,如果处理不好,将会出现无法多次连接和连接关闭后导致僵死进程的情况。在开发过程中,使用popen函数运行一个perl脚本Get_DDTS_Field并将其结果通过管道返回程序,该脚本使用DDTS工具进行数据库查询。这种方法充分利用了已有工具和perl语言的灵活性。为了确保侦听程序始终运行,我们采用的方法是在UNIX主机的系统crontab里添加了一条指令使得系统每隔一分钟检查侦听程序scksvr是否正在运行,并在因系统异常导致其中断运行的情况下重新启动。
使用crontab命令往系统crontab里添加一条指令使得系统每分钟执行一次的特定命令的方法如下:
>crontab
* * * * * /home/ant1/a16635/bin/start_scksvr.sh
有关crontab命令的用法可以查阅UNIX帮助文档。
检查侦听程序scksvr是否在运行的shell脚本start_scksvr.sh如下:
#!/bin/sh
/bin/ps -ef -o comm | grep "^/.*/scksvr" > /dev/null 2>/dev/null
if [ $? -ne 0 ]
then
/home/ant1/a16635/bin/scksvr& > /dev/null 2>/dev/null
fi
客户端运行在Windows NT平台上,采用Microsoft Visual C++的ATL(Active Template Library)模板COM开发和MFC Socket编程做成一个COM组件。使用COM组件可以避免在多个ASP文件中使用Winsock ActiveX控件进行编程,实现代码复用。该COM组件还用于一些VBScript脚本,这些VBScript脚本使用该COM组件并访问本地数据库实现数据的同步。使用Windows NT的Scheduale Server来定时运行这些VBScript脚本实现数据的定时自动同步。
在Visual C++采用ATL模板进行COM组件开发过程如下:在Visual C++的新建对话框里选择Projects面板里的ATL COM AppWizard,输入项目名称按确定后进入ATL COM AppWizard对话框,在ATL COM AppWizard对话框里选中Support MFC以便能够使用CSocket类进行Socket编程。在生成的ATL项目中通过Insert菜单里的New ATL Object新建一个Full Control,Visual C++将自动生成接口定义idl文件和一个与该Full Control对应的类。在ClassView中右键点击新建的Full Control,添加方法或属性,Visual C++将自动在idl文件中添加相应接口,并在其对应类中添加对方法或属性读写的实现的声明和定义。下面要做的就是加入方法或属性读写的实现代码。
使用MFC CSocket类进行Socket编程可以参考CRTool的Connect方法和GetCRField方法的实现代码:
STDMETHODIMP CCRTool::Connect()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
USES_CONVERSION; //string conversion
if(m_bConnected)
return S_OK;
if (!AfxSocketInit())
{
m_bConnected = false;
return S_OK;
}
m_pSocket = new CSocket();
if (!m_pSocket->Create())
{
delete m_pSocket;
m_pSocket = NULL;
m_bConnected = false;
return S_OK;
}
while (!m_pSocket->Connect(OLE2A(m_strHost), m_nPort))
{
delete m_pSocket;
m_pSocket = NULL;
m_bConnected = false;
return S_OK;
}
m_bConnected = true;
return S_OK;
}
STDMETHODIMP CCRTool::GetCRField(VARIANT *pCRNO, short LengthofFieldName, VARIANT *pFieldName, VARIANT *pFieldValue)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
USES_CONVERSION; //string conversion
char SendBuffer[4], ReceiveBuffer[4097];
memset(SendBuffer, 0, 4);
memset(ReceiveBuffer, 0, 4097);
//Send the CRNO
m_pSocket->Send(OLE2A(pCRNO->bstrVal), 10);
m_pSocket->Receive(ReceiveBuffer, 2);
//Length of FieldName
sprintf((char *)SendBuffer, "%3d", LengthofFieldName);
m_pSocket->Send(SendBuffer, 3);
m_pSocket->Receive(ReceiveBuffer, 2);
//Send the FieldName
m_pSocket->Send(OLE2A(pFieldName->bstrVal), LengthofFieldName);
//Receive the FieldValue
memset(ReceiveBuffer, 0, 4097);
m_pSocket->Receive(ReceiveBuffer, 4096);
pFieldValue->bstrVal = SysAllocString(A2OLE(ReceiveBuffer));
/*
A2OLE allocates memory off the stack, which is
automatically freed when your method exits.
You need to use SysAllocString.
*/
return S_OK;
}
使用VARIANT *类型的变量传递GetCRField的返回值是因为在ASP和VBScript脚本中只有VARIANT类型的变量允许按引用传递给COM组件的方法。此外,应该注意在返回结果时应使用SysAllocString来分配内存。
4 结束语
本文分析了在企业安全策略下跨平台数据同步面临的问题和几种数据同步方法,在分析手工同步和开放数据库访问IP端口的利弊基础上提出了一种基于Socket通信的数据同步解决方案。在实现基于Socket通信的数据同步时,根据实现Intranet自动化工具的需要,使用了Visual C++的ATL模板设计了一个Socket客户端COM组件。本文简要介绍了在Windows环境下使用Visual C++的ATL模板进行COM组件开发和使用MFC CSocket类进行Socket编程的方法。
本文同时给出了利用UNIX下的ps命令和grep命令判断某特定程序是否正在运行的技巧和使用crontab命令定时自动运行特定程序的方法,具有一定的参考价值。
参考文献:
1. 如何进行 Socket 编程,http://cgisss.533.net/learn/others/socket.htm
2. Active Template Library (ATL) Reference, MSDN, Microsoft
3. CSocket, Microsoft Foundation Class Library, MSDN, Microsoft
Data Synchronization Over Different Platforms Under Enterprise Security Policy
Geng Changyu1, Zhu Yunwen2, Hong Jiandong2, Ju Ti1
(1.Nanjing University of Post and Telecommunications, Nanjing Jiangsu, 210003; 2. Software Center, Motorola, China,Nanjing Jiangsu, 210029)
Abstract: This paper discusses methods of data synchronization over different platforms. Then it gives an example to illuminate the application of implementation of data synchronization over different platforms under enterprise security policy in the design of intranet automatic tools.
Key Words: Enterprise Security Policy, Intranet Automatic Tools, Socket Communication, Componential Programming
作者简介:
耿昌宇,南京邮电学员计算机科学与技术系硕士研究生,研究方向为计算机数据快速采集与处理;朱允文,摩托罗拉中国软件中心高级程序员;洪建东,摩托罗拉中国软件中心系统分析员;居悌,南京邮电学员计算机科学与技术系教授,硕士研究生导师,研究方向为计算机在TMN中的应用、计算机数据快速采集与处理。
作者会员名:kingmario