第十七夜:编写一个Windows的服务

在Windows中创建服务一般需要先编写服务程序的代码,然后使用SCM注册这个服务。
手动注册一个Windows服务的方法是:

1
2
3
4
5
6
7
8
# 注册服务
sc create TestService binpath= D:\\Programs\\TestService\\main.exe
# 删除服务
sc delete TestService
# 开启服务
net start TestService
# 停止服务
net stop TestService

这里实现了一个最基本的Windows服务程序,服务启动之后监听本地TCP 8888端口,接收和发送数据。

service.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*service.cpp*/


#include <stdio.h>
#include <Windows.h>

#include "service.h"



#define SLEEP_TIME 5000



SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;

void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService();
int WriteToLog(char* str);

int main(int argc, char* argv[]){
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "ServiceExample1";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;

ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;

StartServiceCtrlDispatcher(ServiceTable);
return 0;
}


void ServiceMain(int argc, char** argv){
int error;

ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;

hStatus = RegisterServiceCtrlHandler("ServiceExample1", (LPHANDLER_FUNCTION)ControlHandler);
if (hStatus == (SERVICE_STATUS_HANDLE)0){
// Registering Control Handler failed
return;
}
// Initialize Service
error = InitService();
if (!error){
// Initialization failed
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
return;
}
// We report the running status to SCM.
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);

int server = start_server(8888);
/*
MEMORYSTATUS memory;
// The worker loop of a service
while (ServiceStatus.dwCurrentState == SERVICE_RUNNING){
char buffer[16];
GlobalMemoryStatus(&memory);
sprintf(buffer, "%d", memory.dwAvailPhys);
int result = WriteToLog(buffer);
if (result){
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
return;
}
Sleep(SLEEP_TIME);
}
*/


return;
}


void ControlHandler(DWORD request){
switch(request) {
case SERVICE_CONTROL_STOP:
WriteToLog("服务已停止");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &ServiceStatus);
return;


case SERVICE_CONTROL_SHUTDOWN:
WriteToLog("服务已关闭");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &ServiceStatus);
return;

default:
break;
}

// Report current status
SetServiceStatus (hStatus, &ServiceStatus);
return;
}





int InitService(){
WriteToLog("服务已启动");
return true;
}

server.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*server.cpp*/
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#include "service.h"

#pragma comment(lib,"ws2_32.lib")


int start_server(int bind_port){
//初始化WSA
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0){
return 0;
}

//创建套接字
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (slisten == INVALID_SOCKET){
WriteToLog("Socket创建失败!");
return 0;
}

//绑定IP和端口
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(bind_port);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR){
WriteToLog("Socket绑定失败!");
}

//开始监听
if (listen(slisten, 5) == SOCKET_ERROR)
{
WriteToLog("Socket监听失败!");
return 0;
}

//循环接收数据
SOCKET sClient;
struct sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
//char revData[255];
WriteToLog("Socket监听成功,等待连接...");
sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
while (1){
char revData[255];

char * client_address = inet_ntoa(remoteAddr.sin_addr);

//printf("等待连接...\n");
//sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
if (sClient == INVALID_SOCKET){
WriteToLog("数据接收错误!");
continue;
}
WriteToLog( client_address );

//接收数据
int ret = recv(sClient, revData, 255, 0);
//printf(ret);
if (ret > 0){
//revData[ret] = 0x00;
WriteToLog(revData);
}

//发送数据
char * sendData = revData;
send(sClient, sendData, strlen(sendData), 0);

}
closesocket(sClient);
closesocket(slisten);
WSACleanup();
return 0;
}

utils.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*utils.cpp*/

#include <time.h>
#include <stdio.h>
#include <stdlib.h>


#define LOGFILE "C://service_example_1_log.txt"


int WriteToLog(char* str){
FILE* log;
log = fopen(LOGFILE, "a+");
if (log == NULL)
return -1;

time_t rawtime;
struct tm * timeinfo;
char time_buffer [128];

time (&rawtime);
//printf("%ld\n", rawtime);

timeinfo = localtime (&rawtime);
strftime (time_buffer,sizeof(time_buffer),"%Y/%m/%d %H:%M:%S",timeinfo);
//printf("%s\n", buffer);

fprintf(log, "%s\t%s\n", time_buffer, str);
fclose(log);
return 0;
}

service.h

1
2
3
4
5
/*service.h*/


extern int WriteToLog(char* str);
extern int start_server(int bind_port);

参考资料

开发 Windows 服务应用
C语言开发Windows服务
C++编写Windows服务
C++编写Windows服务
Windows 服务程序(一)
Windows 服务程序(二)
windows环境下C语言socket编程

内网中利用UPNP进行端口映射 第十六夜:编写一个Linux的服务
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×