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

来源:互联网 发布:php include 来源 编辑:程序博客网 时间:2024/05/22 12:59

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)



0 0
原创粉丝点击