您的位置:首页 > 其它

JJY本地服务器以服务方式运行不能读取消息文件

2014-06-24 02:18 441 查看

1.问题描述

JJY主服务器采用Windows服务方式运行时,在读tb_0031消息对应的外部文件时失败.而在控制台方式下正常。

读文件失败的结果是单据没有发送,且错误类型是文件路径不存在(ERROR_PATH_NOT_FOUND).在程序采用忽略该消息记录并删除的逻辑控制下,系统表现出DRP系统的数据已抽取(tb_)但没有发送出去,并且在tb_0031没有痕迹。

这些文件是由DD抽取服务器生成,由主服务器发送给平台,再由平台送抵目标机构.

文件存放主目录是2个服务器共享的.实际环境是在主服务器上的一个共享目录,映射为Y盘.DD抽取服务器的bbox.conf指向该映射盘.

例如,

<!--抽取文件输出目录-->
<export_path>Y:\data\retail\autosend</export_path>


DD抽取服务器在抽取数据生成消息包,保存到tb_0031时,对于超过32k字节大小(可配置)的消息采用外部文件的方式,f007b_0031中保存带路径的文件名。

主服务器SEMQ在发送记录的消息时,直接打开其中内容指向的文件.

dd.conf有以下关于最小外部文件大小的配置:

<!--最小外部文件字节数,默认:8k-->
<ext_file_min_size>10240</ext_file_min_size>


主服务器采用Windows服务方式的原因是,以控制台方式运行,在需要重新启动进程时,直接关闭进程而不是优雅地停止,服务器没有提醒并等待客户端用户保存工作的机会.

基于hotfox的本地服务器在控制台方式下有2种优雅结束的方式:

.Ctrl-C:但为了避免远程控制时操作人员习惯用Ctrl-C复制文本而导致进程意外终止

.ServerManager控制:通过与服务器通信由协议调用IManager接口实现.(目前的实现是直接操纵服务还是通过与服务器通信?)

在JJY的分离部署,主服务器必须采用服务方式的环境需求下,问题归结为:Windows服务方式下如何访问映射盘.

此问题在我的工作机器上可以验证重现。

以下的测试和验证活动都是在我的工作机器上进行的,系统为:Windows Professional XP 2002 SP3.

2.寻求解决之道

根据网上搜索到的资料中,验证以下方法不可行:

(1)linkd/subst/net use

(2)以Administrator启动服务

(3)把NT AUTHORITY\NETWORK SERVICE加入到Administrator组

(4)用srvany,以Administrator启动

instsrv srvany C:\Windows\System32\srvany.exe
用svrany启动服务,注册文件如下:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\instsrv\Parameters]
"AppParameters"="-d"
"Application"="D:\\das\\Retail Server\\hotfoxd.exe"
"AppDirectory"="D:\\das\\Retail Server"


下面2个经过测试看似可行的方法:

1.使用WNetAddConnection2

在插件的Activate方法中利用WNetAddConnection2建立映射盘,在后台线程中可以访问.

NETRESOURCE nr;
DWORD res;
TCHAR szUserName[32] = "administrator",
szPassword[32] = "xxxxx",
szLocalName[32] = "x:",
szRemoteName[MAX_PATH] = "\\\\127.0.0.1\\t";
nr.dwType = RESOURCETYPE_ANY;
nr.lpLocalName = szLocalName;
nr.lpRemoteName = szRemoteName;
nr.lpProvider = NULL;
res = WNetAddConnection2(&nr, szPassword, szUserName, FALSE);


2.使用ImpersonateLoggedOnUser

#include "Tlhelp32.h."
BOOL GetTokenByName(HANDLE &hToken,LPSTR lpName)
{
if(!lpName)
{
return FALSE;
}
HANDLE        hProcessSnap = NULL;
BOOL          bRet      = FALSE;
PROCESSENTRY32 pe32      = {0};

hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
return (FALSE);

pe32.dwSize = sizeof(PROCESSENTRY32);

if (Process32First(hProcessSnap, &pe32))
{
do
{
if(!lstrcmpi(pe32.szExeFile,lpName))
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,
FALSE,pe32.th32ProcessID);
bRet = OpenProcessToken(hProcess,TOKEN_ALL_ACCESS,&hToken);
CloseHandle (hProcessSnap);
return (bRet);
}
}
while (Process32Next(hProcessSnap, &pe32));
bRet = TRUE;
}
else
bRet = FALSE;
CloseHandle (hProcessSnap);
return (bRet);
}

#include <Winnetwk.h>
#pragma comment(lib,"Mpr.lib");
ACE_THR_FUNC_RETURN test_proc(void*) {
do {
GetTokenByName(hToken,"EXPLORER.EXE");
bool br = ImpersonateLoggedOnUser (hToken);
string fn = "X:\\a.txt";
HANDLE handle = CreateFile(fn.c_str(),GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
err = GetLastError();
if (handle!=INVALID_HANDLE_VALUE) {
CloseHandle(handle);
}
RevertToSelf ();
Sleep(3000);
} while(1);
};


方法(1)需要针对服务方式运行增加映射盘配置.

方法(2)ImpersonateLoggedOnUser要在访问映射盘的线程中调用,限制了使用.

这2种方法都不适用.以何种方式运行对程序应该是透明的.或者是外部逻辑.这个问题的产生应属于误用.

以下是2则相关的官方说明:

http://support.microsoft.com/default.aspx?scid=kb;en-us;827421#appliesto

A service that runs under a LocalSystem account or under a local user account can only access mapped drives that the service creates. Mapped drives are stored for each logon session. If a service runs under a LocalSystem account or under a local user account
that does not create certain mapped drives, the service cannot access these mapped drives. Additionally, a service that runs under a local user account that creates certain mapped drives also receives a new set of mapped drives if you log off and then you
log on again as the same local user.

服务只能访问服务自己创建的映射盘.

http://support.microsoft.com/kb/180362/en-us

A service should not directly access local or network resources through mapped drive letters. Additionally, a service should not use the WNetXXXXXXX APIs to add, remove, or query any mapped drive letters. Although the WNetXXXXXXX APIs may return successfully,
the results will be incorrect. A service (or any process that is running in a different security context) that must access a remote resource should use the Universal Naming Convention (UNC) name to access the resource. UNC names do not suffer from the limitations
described in this article.

不应该使用WNetXXXXXXX API.应该使用UNC.

备忘资料:

How to map a network drive to be used by a service

3.处理对策

鉴于上述的测试结果和官方说明,结合实际情况提出以下处理方案:

(1)以console方式运行:

hotfox增加<enable_control_c>配置,控制是否允许Ctrl-C终止进程,仅对console有效.

<!--是否允许Ctrl-C终止进程,默认:true -->
<enable_contol_c>false</enable_control_c>


(2)完善ServerManager支持远程控制hotfox停止

通过170-Request请求停止服务器.

这需要检查程序后确定或者修改以支持

(3)路径配置采用UNC

以后此类分离部署需要共享的目录采用UNC方式.

如:

<!--抽取文件输出目录-->
<export_path>\\127.0.0.1\share\data\retail\autosend</export_path>


对于目前正在运行的系统,由于有历史记录需要处理,不能采用此方式.

所以,如果保持采用服务方式,并且考虑历史数据处理,采用以下临时方法过渡.

(4)临时方法:服务运行时创建映射盘

。更新bbox.dll.

。修改bbox.conf配置,增加以下内容:

<map_drive>
<log_user>administrator</log_user> <!-- 登录帐号 -->
<pswd>test123</pswd> <!-- 帐号密码 -->
<drive>X:</drive> <!--驱动器盘符 -->
<remote>\\127.0.0.1\t</remote> <!--共享目录 -->
</map_drive>
。修改服务登录身份,以登录帐号用户运行,默认是本地系统帐户(LocalSystem)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐