企业安全策略下的跨平台数据同步 (转摘)
转摘
企业安全策略下的跨平台数据同步
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数据库中指定纪录的字段值为例):
2{
3 signal(SIGCHLD,fireman);
4 while (waitpid(-1, NULL, WNOHANG) > 0)
5 ;
6}
7
8int main()
9{
10 /*
11 ……
12 变量声明、初始化
13 */
14
15 signal(SIGCHLD,fireman); /* 指定信号处理句柄以清除僵死进程 */
16
17 if ((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
18 {
19 return printf("Can not open TCP SOCKET!\n");
20 }
21
22 bzero((char *)&serv_addr,sizeof(serv_addr));
23 serv_addr.sin_family=AF_INET;
24 serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
25 serv_addr.sin_port=htons(portnum); /* 指定端口号 */
26
27 if (bind(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0)
28 {
29 return printf("Bind SOCKET error!\n");
30 }
31
32 listen(sockfd,5);
33
34 for(; ;)
35 {
36 if ((newsockfd=accept(sockfd)) < 0) /* 建立连接 */
37 {
38 if (errno == EINTR) /* EINTR might happen on accept(), */
39 {
40 continue; /* try again */
41 }
42
43 return printf("Can not accept newsocket\n"); /* bad */
44
45 EXIT(1);
46 }
47
48 if ((childpid=fork())==0)
49 {
50 close(sockfd);
51 socketopen = 1;
52 while(socketopen == 1)
53 {
54 Readn(newsockfd,buf,10);
55 buf[10] = 0;
56 strcpy(cr_no,buf);
57 Writen(newsockfd,"OK",2);
58 Readn(newsockfd,buf,3);
59 buffer[3] = 0;
60 len = atoi(buf);
61 Writen(newsockfd,"OK",2);
62 Readn(newsockfd,buf,len);
63 buf[len] = 0;
64 strcpy(field_name,buf); /* 获取Socket请求数据 */
65 strcpy(cmd,HOME);
66 strcat(cmd,"Get_DDTS_Field defects ");
67 strcat(cmd,cr_no);
68 strcat(cmd," ");
69 strcat(cmd,field_name);
70 ptr = popen(cmd,"r"); /* 运行查询脚本 */
71 memset(buf,0,BUFSIZ);
72 I = fread(buf,BUFSIZ,1,ptr);
73
74 if (strlen(buf) == 0)
75 {
76 strcpy(buf,"Not Exist! ");
77 }
78
79 Writen(newsockfd,buf,strlen(buf)-1);/* 发送查询结果 */
80 pclose(ptr);
81 }
82
83 EXIT(0);
84 }
85 else
86 {
87 close(newsockfd);
88 }
89
90 continue;
91 }
92}
代码中,对建立连接是产生的EINTR错误的处理和对SIGCHLD信号的处理是关键,如果处理不好,将会出现无法多次连接和连接关闭后导致僵死进程的情况。在开发过程中,使用popen函数运行一个perl脚本Get_DDTS_Field并将其结果通过管道返回程序,该脚本使用DDTS工具进行数据库查询。这种方法充分利用了已有工具和perl语言的灵活性。为了确保侦听程序始终运行,我们采用的方法是在UNIX主机的系统crontab里添加了一条指令使得系统每隔一分钟检查侦听程序scksvr是否正在运行,并在因系统异常导致其中断运行的情况下重新启动。
使用crontab命令往系统crontab里添加一条指令使得系统每分钟执行一次的特定命令的方法如下:
* * * * * /home/ant1/a16635/bin/start_scksvr.sh
有关crontab命令的用法可以查阅UNIX帮助文档。
检查侦听程序scksvr是否在运行的shell脚本start_scksvr.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方法的实现代码:
2{
3 AFX_MANAGE_STATE(AfxGetStaticModuleState())
4
5 USES_CONVERSION; //string conversion
6
7 if(m_bConnected)
8 {
9 return S_OK;
10 }
11
12 if (!AfxSocketInit())
13 {
14 m_bConnected = false;
15 return S_OK;
16 }
17
18 m_pSocket = new CSocket();
19
20 if (!m_pSocket->Create())
21 {
22 delete m_pSocket;
23 m_pSocket = NULL;
24 m_bConnected = false;
25 return S_OK;
26 }
27
28 while (!m_pSocket->Connect(OLE2A(m_strHost), m_nPort))
29 {
30 delete m_pSocket;
31 m_pSocket = NULL;
32 m_bConnected = false;
33 return S_OK;
34 }
35
36 m_bConnected = true;
37
38 return S_OK;
39}
40
41STDMETHODIMP CCRTool::GetCRField(VARIANT *pCRNO, short LengthofFieldName, VARIANT *pFieldName, VARIANT *pFieldValue)
42{
43 AFX_MANAGE_STATE(AfxGetStaticModuleState())
44
45 USES_CONVERSION; //string conversion
46
47 char SendBuffer[4], ReceiveBuffer[4097];
48
49 memset(SendBuffer, 0, 4);
50 memset(ReceiveBuffer, 0, 4097);
51
52 //Send the CRNO
53 m_pSocket->Send(OLE2A(pCRNO->bstrVal), 10);
54 m_pSocket->Receive(ReceiveBuffer, 2);
55 //Length of FieldName
56 sprintf((char *)SendBuffer, "%3d", LengthofFieldName);
57 m_pSocket->Send(SendBuffer, 3);
58 m_pSocket->Receive(ReceiveBuffer, 2);
59 //Send the FieldName
60 m_pSocket->Send(OLE2A(pFieldName->bstrVal), LengthofFieldName);
61 //Receive the FieldValue
62 memset(ReceiveBuffer, 0, 4097);
63 m_pSocket->Receive(ReceiveBuffer, 4096);
64 pFieldValue->bstrVal = SysAllocString(A2OLE(ReceiveBuffer));
65 /*
66 A2OLE allocates memory off the stack, which is
67 automatically freed when your method exits.
68 You need to use SysAllocString.
69 */
70
71 return S_OK;
72}
73
使用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中的应用、计算机数据快速采集与处理。
看到这篇文章,他这样解决是由于是在不同的系统中操作系统,或不同的数据库中,还是由于在INTERNET中才出现用编程的方法来实现这点的呢?
那位高手请讲讲,在什么时候用数据库的本身的工具就能实现数据的同步,什么时候就要考虑用exe程序来实现。
/*************************************************************
我是搞ORACLE的,SQL SERVER只是入门级水准。但我想很多东西都是共通的。希望我的意见不打扰你。
1、有这样的应用:有多个数据库必须保持完全同步,比如DNS服务器。但对一般商用系统来说,很少见到多个数据库保持完全一样的数据,除非是备份数据库。
2、我公司的应用就属于后一种情况。多达100个数据库服务于各个地区和部门,因为启用时间有很大的差异,所以版本也不完全一样(ORACLE 7.0/7.2/7.34/8.05/8I都有)。数据库中的信息分为几类:其中有一部分(大约1/10)的基本数据是需要全球统一的,另外大约有1/4是完全用于本地的,其它超过1/2的数据在多个数据库中相互交换。比如,第一类:比如总部会发送所有的产品信息到所有的数据库;第二类:例如仓库中的具体库存位置是完全本地化的。第三类:也是最多的一类,例如一家商店的订单信息会传到地区中心,地区中心会根据不同的订单类型发去不同的地区/部门,比如向欧洲订货就只把订单传去欧洲的TRADING部门和财务部门,而不需要传给美洲。
3、如果能让每个数据库的内容保持一致当然最好,但这需要花费大量的人力物力,成本之高不可想象。甚至我怀疑这么大的通讯量能不能保持稳定的传输。
4、我们现在的解决方案是通过EDI进行数据交换,数据库中的每个表都会放数个表示最后更新时间的标志,当系统发送或接受数据的时候,会根据更新时间UPDATE/INSERT记录。这种方法当然是很有效也是很稳定的的,但是有大量的EDI标准需要控制(我们叫AGREEMENT),还有大量的发送/接受代码完全要手工编写。
5、如果你的系统需要对实时性要求很高,这种方法是很难用的,但我们现在还没有很好同时不是花费特别大的方案。
/**********************************************
不知道的机器是怎么布置的,如果两台机器在一起的话可以采用SQL SERVER 中的STAND BY SERVER来实现这个功能,它实际上实现的是实时的双机热备份,如果主机出了问题的话可以把从机启动并把机器名改成和主机一样就可以代替主机运行。当然你可以采用推-拉定制方式复制数据库,不过这种一般是一对多的或是多机之间数据同你好用,比如你修改了A机,B机可以与A机同H步,修改了B机,B机可以与A机同步。如果你只是要复制某些表的某些字段的话最好是用触发器。
至于DTS我不是很喜欢用,所以在这里就不用推荐。