Windows服务可以运行TCP服务器吗?

时间:2013-08-12 13:14:32

标签: c++ visual-studio service tcp windows-services

我使用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");

}

2 个答案:

答案 0 :(得分:0)

您的具体问题的答案是,是的,Windows服务可以运行TCP服务器。

你的原因不起作用的答案尚不清楚。乍一看,服务代码看起来很合理。您的操作系统防火墙可能会阻止与您的服务的连接(即您的控制台位于接受列表中,但您的服务不是)。您可以将一些错误printf逻辑转换为打印到文件的内容(例如fprintf?),这样您就可以了解正在发生的事情......

答案 1 :(得分:0)

当然可以。为什么不可能?

相关问题