文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>Windows服务程序一例

Windows服务程序一例

时间:2007-01-18  来源:rockins

Windows服务程序一例

(陈云川 [email protected] 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);
}

相关阅读 更多 +
排行榜 更多 +
儿童学英语

儿童学英语

学习教育 下载
今天开始生存

今天开始生存

动作格斗 下载
飞碟快闪

飞碟快闪

动作格斗 下载