我使用visual studio 2008在c ++中创建了2个程序:基于此service的Windows服务,我添加了tcp服务器代码和使用MFC的客户端程序,它有一个显示ip地址和主机名的列表框运行该服务的计算机。然后,用户选择服务器并单击连接按钮。由于将运行许多服务器,我在Web主机站点上使用了一些PHP脚本。服务将其IP地址和主机名发送到Web主机,Web主机将信息放入列表中,然后客户端访问此列表。
所有这一切都可以正常使用服务器代码,但是当我将服务器代码放入Windows服务时,客户端程序冻结并且在单击连接按钮时不响应。 IP地址和主机名仍然出现在客户端列表框中,我只是无法连接到我选择的服务器。
Windows服务阻止服务器代码工作吗? 这是包含服务程序中服务器代码的cpp文件:
char* WebPost(char Website[], char Webpage[], char Request[], int RetLen)
{
// Sends an HTTP Post request with POST Data...
SOCKET WebSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct hostent *WebHost;
WebHost = gethostbyname(Website);
if (WebHost == NULL)
{
if (WSAGetLastError() == WSANOTINITIALISED)
printf("Error Not Connected!");
else
printf("Error: %d", WSAGetLastError());
Sleep(1000);
exit(0);
}
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)WebHost->h_addr);
connect(WebSocket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr));
char PostRequest[1024];
sprintf(PostRequest,
"POST %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Content-Length: %hu\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"\r\nD=%s\0",
Webpage, Website,
strlen(Request)+2, Request
);
send(WebSocket, PostRequest, strlen(PostRequest), 0);
// Get return data
char* Data = new char[RetLen];
recv(WebSocket, Data, 4, 0);
for (;;)
{ // Skip HTTP headers
Data[0] = Data[1];
Data[1] = Data[2];
Data[2] = Data[3];
recv(WebSocket, &Data[3], 1, 0);
if (Data[0] == '\r' && Data[1] == '\n'
&& Data[2] == '\r' && Data[3] == '\n')
break;
}
int DataLen = recv(WebSocket, Data, RetLen, 0);
Data[DataLen] = '\0'; // Return the data
shutdown(WebSocket, 2);
closesocket(WebSocket);
return Data;
}
void ServStart()
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
printf("WSAStartup failed with error %ld.\n", WSAGetLastError());
exit(0);
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion));
WSACleanup();
exit(0);
}
//Start listening
ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListeningSocket == INVALID_SOCKET)
{
printf("Error at socket, error code: %ld.\n", WSAGetLastError());
WSACleanup();
exit(0);
}
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(Port);
ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
{
printf("bind failed. Error code: %ld.\n", WSAGetLastError());
closesocket(ListeningSocket);
WSACleanup();
exit(0);
}
if (listen(ListeningSocket, 5) == SOCKET_ERROR)
{
printf("listen: Error listening on socket %ld.\n", WSAGetLastError());
closesocket(ListeningSocket);
WSACleanup();
exit(0);
}
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
{
printf("Error when getting local host name: ", WSAGetLastError());
exit(0);
}
struct hostent *phe = gethostbyname(ac);
if (phe == 0)
{
printf("Error: ", WSAGetLastError());
exit(0);
}
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr)); // use the first ip-address
printf("IP used by Server: %s\n", inet_ntoa(addr)); // inet_ntoa(addr) provides the local address.
MyIP = inet_ntoa(addr);
char SendBuf[32];
// * is used as a separator, because it's not allowed in the hostname.
//So it won't interfere with it.
sprintf(SendBuf, "%hhu|%s*%s", cAddIP, MyIP, ac); // Send the server the IP and host name
WebPost(WEBSITE, WEBPAGE, SendBuf, 0);
printf("listening for connections...\n\n");
}
void ShutDown() // Shut down the server (tells the web server I am offline)
{
char SendBuf[32]; // Remove my IP from the list of online servers...
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
{
printf("Error when getting local host name: ", WSAGetLastError());
exit(0);
}
sprintf(SendBuf, "%hhu|%s*%s", cRemIP, MyIP,ac);
WebPost(WEBSITE, WEBPAGE, SendBuf, 0);
printf("Successful shutdown\n");
Sleep(1000);
WSACleanup();
}
void ServLoop()
{
SOCKADDR_IN SenderInfo;
SOCKET NewConnection;
int ByteReceived, nlen;
char recvbuff[1024];
for (;;)
{
//Main program loop
NewConnection = SOCKET_ERROR;
while(NewConnection == SOCKET_ERROR)
{
NewConnection = accept(ListeningSocket, NULL, NULL); // this is a blocking function
printf("New client got connected, ready to receive and send data...\n\n");
ByteReceived = recv(NewConnection, recvbuff, sizeof(recvbuff), 0);
if (ByteReceived > 0)
{
getsockname(ListeningSocket, (SOCKADDR *)&ServerAddr, (int *)sizeof(ServerAddr));
memset(&SenderInfo, 0, sizeof(SenderInfo));
nlen = sizeof(SenderInfo);
getpeername(NewConnection, (SOCKADDR *)&SenderInfo, &nlen);
}
}
if (shutdown(NewConnection, 2) != 0)
printf("there is something wrong with the shutdown. The error code: %ld\n", WSAGetLastError());
else
printf("shutdown is working...\n");
}
}
// --------------------------------------------
BOOL ConsoleProc(DWORD Msg)
{
switch (Msg)
{
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
ShutDown();
return false;
}
return false;
}
// -----------------------------------------------------
CSampleService::CSampleService(PWSTR pszServiceName,
BOOL fCanStop,
BOOL fCanShutdown,
BOOL fCanPauseContinue) :
CServiceBase(pszServiceName, fCanStop, fCanShutdown, fCanPauseContinue),
m_dwTimeout(10 * 1000)
{
// Create a manual-reset event that is not signaled at first to indicate
// the service is stopping.
m_hStoppingEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hStoppedEvent == NULL)
{
throw GetLastError();
}
// Create a manual-reset event that is not signaled at first to indicate
// the stopped signal of the service.
m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hStoppedEvent == NULL)
{
throw GetLastError();
}
}
CSampleService::~CSampleService(void)
{
if (m_hStoppedEvent)
{
CloseHandle(m_hStoppedEvent);
m_hStoppedEvent = NULL;
}
if (m_hStoppingEvent)
{
CloseHandle(m_hStoppingEvent);
m_hStoppingEvent = NULL;
}
}
void CSampleService::OnStart(DWORD dwArgc, LPWSTR *lpszArgv)
{
WriteErrorLogEntry(L"CSampleService::Start: function entry");
// Log a service start message to the Application log.
WriteEventLogEntry(L"CppWindowsService in OnStart", EVENTLOG_INFORMATION_TYPE);
// Queue the main service function for execution in a worker thread.
CThreadPool::QueueUserWorkItem(&CSampleService::ServiceWorkerThread, this);
WriteErrorLogEntry(L"CSampleService::Start: function exit");
}
void CSampleService::ServiceWorkerThread(void)
{
WriteErrorLogEntry(L"CSampleService::ServiceWorkerThread: running");
// Periodically check if the service is stopping.
while (WaitForSingleObject(m_hStoppingEvent, m_dwTimeout) == WAIT_TIMEOUT)
{
// Perform main service function here...
// Handle console events
SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleProc, TRUE);
ServStart(); // Main loop is in another thread
ServLoop(); // The never returning server loop
}
// Signal the stopped event.
SetEvent(m_hStoppedEvent);
WriteErrorLogEntry(L"CSampleService::ServiceWorkerThread: done");
}
void CSampleService::OnStop()
{
ShutDown(); //shut down server
SetServiceStatus(SERVICE_STOP_PENDING, ERROR_SUCCESS, 30 * 1000);
WriteErrorLogEntry(L"CSampleService::Stop: function entry");
// Log a service stop message to the Application log.
WriteEventLogEntry(L"CppWindowsService in OnStop", EVENTLOG_INFORMATION_TYPE);
// Indicate that the service is stopping and wait for the finish of the
// main service function (ServiceWorkerThread).
SetEvent(m_hStoppingEvent);
if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
{
SetServiceStatus(SERVICE_STOP_PENDING, ERROR_INVALID_DATA, 30 * 1000);
WriteErrorLogEntry(L"OnStop: Service Start", GetLastError());
throw GetLastError();
}
WriteErrorLogEntry(L"CSampleService::Stop: function exit");
}
答案 0 :(得分:0)
您的具体问题的答案是,是的,Windows服务可以运行TCP服务器。
你的原因不起作用的答案尚不清楚。乍一看,服务代码看起来很合理。您的操作系统防火墙可能会阻止与您的服务的连接(即您的控制台位于接受列表中,但您的服务不是)。您可以将一些错误printf
逻辑转换为打印到文件的内容(例如fprintf
?),这样您就可以了解正在发生的事情......
答案 1 :(得分:0)
当然可以。为什么不可能?