免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1027 | 回复: 0
打印 上一主题 下一主题

Windows服务程序一例 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-01-18 05:34 |只看该作者 |倒序浏览

Windows服务程序一例
(陈云川
ybc2084@163.com
UESTC,CD)
1 起因
事情的起因是这样的:我有两台机器,不妨假定为机器A和机器B,两台机器处于不同的网络中。其中,主机A所在的网络采用DHCP动态分配IP地址,主机B采用手动指定的静态IP地址。大多数情况下我在B主机上工作,但是经常需要远程登录到A主机获取资料。现在,A主机上运行的是Windows XP,远程登录方式为RDP。
面临的一个问题是:每次当我请别人帮我把A主机启动之后,由于A主机所在的网络采用DHCP动态分配IP地址,因此我就不得不让人登录进系统,查看了IP地址之后再告诉我。一次两次倒还可以接受,次数多了,就嫌麻烦。既然我常用的B主机的IP地址是固定的,那么我就希望每次A主机启动之后能够自动把IP地址通报给B主机,这样我就不用再麻烦了。怎么办呢?我当然首先想到了守护进程。不过Windows下没有守护进程的概念,取而代之的是服务(service)。那么,就编写一个简单的服务程序罢,每次机器启动之后自动连接到B主机的某个UDP端口上(本例中连接到UDP端口8277),而运行在B主机上的服务程序就可以打印出A主机的IP地址了。如此,不管DHCP给A主机分配的IP地址怎么变,我再也不用浪费时间在搞到A主机的IP地址这种琐碎的事情上了。
之前并没有接触过Windows服务程序的编写,不过既然都遇到了。那么就看看文档吧。Windows提供了一大堆API用于服务程序的编写,如下所示:

ChangeServiceConfig
CloseServiceHandle
ControlService
CreateService
DeleteService
EnumDependentServices
EnumServicesStatus
GetServiceDisplayName
GetServiceKeyName
Handler
LockServiceDatabase
NotifyBootConfigStatus
OpenSCManager
OpenService
QueryServiceConfig
QueryServiceLockStatus
QueryServiceObjectSecurity
QueryServiceStatus
RegisterServiceCtrlHandler
ServiceMain
SetServiceBits
SetServiceObjectSecurity
SetServiceStatus
StartService
StartServiceCtrlDispatcher
UnlockServiceDatabase

不过我用不了这么多,给我一套最小的工作集合足矣!我只需要下面这些API:

StartServiceCtrlDispatcher()
ServiceMain()
RegisterServiceCtrlHandler()
SetServiceStatus()
Handler()

加上这样几个结构体:

SERVICE_TABLE_ENTRY
SERVICE_STATUS_HANDLE
SERVICE_STATUS

万事俱备!
2 发送端实现
发送端的实现在ipnotify_cli.c文件中。抛开Windows服务程序编写的相关规范来看,程序本身是很简单的,就是一个只发不收的UDP程序而已。简单得让人不忍赘述。另外,作者是用DEV-CPP编译该程序的,需要链接libws2_32.a,这个库文件中包含了Windows的套接口函数的实现。编译得到的程序是不能直接运行的,必须要注册为服务之后从Windows服务管理器中启动才行。有关服务注册和启动,请google之。附件中的SRVINSTW.exe是用来安装服务的,使用非常简单,请大胆实践。
3 接收端实现
作者所用的B主机为一台运行Linux的机器,因此,接收端的程序是采用Linux的套接口函数来编写的。当然,无论是Linux还是Windows,套接口都是相似的,但是差别总还是有那么一些。附件中一并附上接收端的源代码实现ipnotify_svr.c。
4 结论
个人感觉,在Windows下弄一个守护进程始终要比Unix类系统下麻烦一些。不过也可能是我不习惯罢了。
5 参考
[1] Microsoft®Win32®Programmer's Reference
[2] man socket(2)等

附:
ipnotify_cli.c的实现:

/*
  Name: ipnotify_cli.c
  Copyright: ultimate free
  Author: rockins
  Date: 18-01-07 04:46
  Description:     a windows service, which will notify local IP address
                  to a remote supervisor
*/
#include stdio.h>
#include stdlib.h>
#include windows.h>
#define    REM_HOST    "202.115.26.*"        /*my linux box, as supervisor host*/
#define    REM_PORT    8277                /*8277, someone's birthday, as port*/
#define BUFF_SIZE    8192                /*packet data maximum length*/
#define    FINGERPRINT    "this is packet is from rockins\n"    /*identification*/
signed int ipnotify_status = 1;            /*service status:
                                               0    inactive
                                            1    active
                                          */
SERVICE_STATUS_HANDLE ipnotify_status_handle;
SERVICE_STATUS ipnotify_service_status;
/*
* prototype:
*     VOID WINAPI Handler(
*         DWORD fdwControl     // requested control code
*     );
*/
VOID WINAPI
ipnotify_handler(DWORD fdwControl)
{
    if (fdwControl == SERVICE_CONTROL_STOP)
        ipnotify_status = 0;
    if (fdwControl == SERVICE_CONTROL_PAUSE)
        ipnotify_status = 0;
    if (fdwControl == SERVICE_CONTROL_CONTINUE)
        ipnotify_status = 1;
    if (fdwControl == SERVICE_CONTROL_INTERROGATE)
        ;                        // I donot know how to deal with this
    if (fdwControl == SERVICE_CONTROL_SHUTDOWN)
          ipnotify_status = 0;
}
/*
* prototype:
*        VOID WINAPI ServiceMain(
*         DWORD dwArgc,    // number of arguments
*         LPTSTR *lpszArgv     // address of array of argument string pointers
*     );
*/
VOID WINAPI
ipnotify_main(DWORD dwArgc, LPTSTR *lpszArgv)
{
    WSADATA    wsData;                        /*Windows Socket Application*/
    SOCKET    sock;                        /*socket object*/
    struct sockaddr_in svr_addr;        /*server socket address*/
    int svr_addr_len;                    /*length of server addr*/
    int err;                            /*save error code*/
    int err_time = 0;                    /*error times*/
    int len;                            /*length of packet data*/
    char buff[BUFF_SIZE];                /*packet data*/
   
    /*register service*/
    ipnotify_status_handle = RegisterServiceCtrlHandler("ipnotify",
                                            &ipnotify_handler);
   
    /*update service status*/
    ipnotify_service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    ipnotify_service_status.dwCurrentState = SERVICE_RUNNING;
    ipnotify_service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    ipnotify_service_status.dwWin32ExitCode = NO_ERROR;
    ipnotify_service_status.dwServiceSpecificExitCode = 0;
    ipnotify_service_status.dwCheckPoint = 0;
    ipnotify_service_status.dwWaitHint = 0;
    if (!SetServiceStatus(ipnotify_status_handle, &ipnotify_service_status)) {
        printf("SetServiceStatus()\n");
        exit(-1);
    }
   
    /*init sending buffer*/
    memset(buff, 0, BUFF_SIZE);
    strncpy(buff, FINGERPRINT, BUFF_SIZE);
   
    /*init network subsystem of win32*/
    err = WSAStartup(MAKEWORD(2, 2), &wsData);
    if (err) {
        printf("cannot init winsock lib...\n");
        exit(-1);
    }
   
    /*create socket object*/
    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (sock == INVALID_SOCKET) {
        printf("cannot create socket...\n");
        exit(-1);
    }
   
    /*stuff the server socket address*/
    memset(&svr_addr, 0, sizeof(svr_addr));
    svr_addr.sin_family = AF_INET;
    svr_addr.sin_port = htons(REM_PORT);
    svr_addr.sin_addr.s_addr = inet_addr(REM_HOST);
   
    /*main loop*/
    while (TRUE) {
        if (ipnotify_status == 0)
            break;
        len = sendto(sock, buff, strlen(buff), 0,
                (struct sockaddr *)&svr_addr, svr_addr_len);
        if (len == SOCKET_ERROR) {
              err = WSAGetLastError();
            printf("error(%d) occured in recvfrom()...\n", err);
            exit(-1);
        }
        
        printf("send fingerprint to the supervisor\n");
        Sleep(2000);
      }
}
int
main(int argc, char *argv[])
{
    SERVICE_TABLE_ENTRY    ipnotify_entry[] = {
        {"ipnotify", ipnotify_main},
        {NULL, NULL}
    };
   
    if (!StartServiceCtrlDispatcher(ipnotify_entry)) {
        printf("StartServiceCtrlDispatcher()\n");
        exit(-1);
    }
   
    system("pause");
    return (0);
}
ipnotify_svr.c的实现:
/*
  Name: ipnotify_svr.c
  Copyright: completely free
  Author: rockins
  Date: 18-01-07 05:11
  Description: receive IP notify from another Windows box
*/
#include stdio.h>
#include stdlib.h>
#include sys/types.h>
#include sys/socket.h>
#include netinet/in.h>
#define    LISTEN_PORT        8277        /*someone's birthday, as port*/
#define    FINGERPRINT        "this is packet is from rockins\n"    /*identification*/
#define    BUFF_SIZE        8192        /*buffer size for incoming data*/
int
main(int argc, char *argv[])
{
    int sock;
    struct sockaddr_in listen_addr;
    struct sockaddr_in peer_addr;
    int listen_addr_len;
    int peer_addr_len;
    char buff[BUFF_SIZE];
    char rcv_len;
    /*create socket descriptor*/
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock  0) {
        perror("socket()");
        exit(-1);
    }
    /*stuff socket address structure*/
    memset(&listen_addr, 0, sizeof(listen_addr));
    listen_addr.sin_family = AF_INET;
    listen_addr.sin_port = htons(LISTEN_PORT);
    listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    /*bind to local listening UDP port*/
    if (bind(sock, (struct sockaddr *)&listen_addr,
                sizeof(listen_addr))  0) {
        perror("bind()");
        exit(-1);
    }
    /*main loop, exit when get what wanted*/
    while (1) {
        rcv_len = recvfrom(sock, buff, BUFF_SIZE, 0,
                (struct sockaddr *)&peer_addr, &peer_addr_len);
        if (rcv_len  0) {
            perror("recvfrom()");
            exit(-1);
        }
        if (!strncmp(buff, FINGERPRINT, BUFF_SIZE)) {
            printf("rockins's box: %s\n",
                    inet_ntoa(peer_addr.sin_addr));
            exit(0);
        }
    }
    return (0);
}


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/270/showart_233850.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP