2011-03-14 23 views
1

我想學習使用在線教程的winsock編程。本示例來自MSDN庫,儘管已修改。我已編譯它,它似乎工作正常,只有一個請求。處理完單個請求後,服務器退出。我已閱讀處理多個請求,並使服務器持久化可以通過線程完成,但不知道如何做到這一點,並沒有在互聯網上找到有用的例子。請幫忙。C Prog - 保持Web服務器不斷偵聽

#undef UNICODE 

#define WIN32_LEAN_AND_MEAN 

#include <windows.h> 
#include <winsock2.h> 
#include <ws2tcpip.h> 
#include <stdlib.h> 
#include <stdio.h> 

// Need to link with Ws2_32.lib 
#pragma comment (lib, "Ws2_32.lib") 
// #pragma comment (lib, "Mswsock.lib") 

#define DEFAULT_BUFLEN 4096 
#define DEFAULT_PORT "27015" 
char recvbuf[DEFAULT_BUFLEN]; 

void handleBuffer() 
{ 
recvbuf[DEFAULT_BUFLEN-1]='\0'; 
printf("\n************The server has received the following request***************\n"); 
printf("%s",recvbuf); 
} 

int __cdecl main(void) 
{ 
WSADATA wsaData; 
SOCKET ListenSocket = INVALID_SOCKET, 
     ClientSocket = INVALID_SOCKET; 
struct addrinfo *result = NULL,hints; 
char* sendbuf = "HTTP/1.0 200 OK\r\nServer: Test\r\nContent-Type: text/HTML\r\n\r\n<html><title>Test Server</title><body><span style=\"color:#2032DC; font-family:arial; font-size:large; position:absolute; left:4%;\">This is test server responding.</span></body></html>"; 
int iResult, iSendResult; 
int recvbuflen = DEFAULT_BUFLEN; 
char e; 

// Initialize Winsock 
iResult = WSAStartup(MAKEWORD(2,2), &wsaData); 
if (iResult != 0) { 
    printf("WSAStartup failed with error: %d\n", iResult); 
    return 1; 
} 
else 
    printf("\nInitialising winsock...done"); 

ZeroMemory(&hints, sizeof(hints)); 
hints.ai_family = AF_INET; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_protocol = IPPROTO_TCP; 
hints.ai_flags = AI_PASSIVE; 
printf("\n"); 

// Resolve the server address and port 
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result); 
if (iResult != 0) { 
    printf("getaddrinfo failed with error: %d\n", iResult); 
    WSACleanup(); 
    return 1; 
} 
else 
    printf("\nResolving server address...done"); 
//localhost:27015/ 
// Create a SOCKET for connecting to server 

ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 
if (ListenSocket == INVALID_SOCKET) { 
    printf("socket failed with error: %ld\n", WSAGetLastError()); 
    freeaddrinfo(result); 
    WSACleanup(); 
    return 1; 
} 
else 
    printf("\nCreating connection socket...done"); 

// Setup the TCP listening socket 
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); 
if (iResult == SOCKET_ERROR) { 
    printf("bind failed with error: %d\n", WSAGetLastError()); 
    freeaddrinfo(result); 
    closesocket(ListenSocket); 
    WSACleanup(); 
    return 1; 
} 
else 
    printf("\nCreating listening socket...done"); 
    printf("\nWaiting for connection... "); 

freeaddrinfo(result); 

iResult = listen(ListenSocket, SOMAXCONN); 

if (iResult == SOCKET_ERROR) { 
    printf("listen failed with error: %d\n", WSAGetLastError()); 
    closesocket(ListenSocket); 
    WSACleanup(); 
    return 1; 
} 

    // Accept a client socket 
    ClientSocket = accept(ListenSocket, NULL, NULL); 
    if (ClientSocket == INVALID_SOCKET) { 
     printf("accept failed with error: %d\n", WSAGetLastError()); 
     closesocket(ListenSocket); 
     WSACleanup(); 
     return 1; 
    } 

    // No longer need server socket 
    closesocket(ListenSocket); 

    iResult = recv(ClientSocket, recvbuf, recvbuflen,0); 
    if (iResult > 0) 
    { 
     printf("Bytes received: %d\n", iResult); 
    } 
    else if (iResult == 0) 
     printf("Connection closing...\n"); 
    else 
    { 
     printf("recv failed with error: %d\n", WSAGetLastError()); 
     closesocket(ClientSocket); 
     WSACleanup(); 
     return 1; 
    } 


    iSendResult = send(ClientSocket,sendbuf,(int)strlen(sendbuf), 0); 
     if (iSendResult == SOCKET_ERROR) 
     { 
      printf("send failed with error: %d\n", WSAGetLastError()); 
      closesocket(ClientSocket); 
      WSACleanup(); 
      return 1; 
     } 
    printf("Bytes sent: %d\n", iSendResult); 
    handleBuffer(); 

    // shutdown the connection since we're done 
    iResult = shutdown(ClientSocket, SD_SEND); 
    if (iResult == SOCKET_ERROR) { 
     printf("shutdown failed with error: %d\n", WSAGetLastError()); 
     closesocket(ClientSocket); 
     WSACleanup(); 
     return 1; 
    } 
// cleanup 
closesocket(ClientSocket); 
WSACleanup(); 
printf("\n\nPress any key to quit."); 

getch(); 
return 0; 
} 
+0

我希望服務器在代碼執着,目前,一個服務請求後,服務器達到回報0和關閉。我想修改代碼,以便服務器可以不斷監聽新的或重複的連接,即使一個請求已經被服務並且沒有關閉。一些猜測的while循環放置沒有幫助。 – check123 2011-03-14 12:26:45

回答

1

這很簡單。

ClientSocket = accept(ListenSocket, NULL, NULL); 

這將返回使用該連接的客戶端通信的插座,所有你需要做的就是做一個讀/寫循環用於此插口,並堅持到一個新的線程。同時,讓你的主循環在accept()上。

什麼是你不明白?

編輯

假設你要使用POSIX線程,看看這個 http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html

掌握在這之後,你可能需要更多的權力和靈活性:看看這個http://www.lowtek.com/sockets/select.html

您可以使用select避免使用線程,你可以用它通過線程來分發您的客戶端(如1..N客戶端/由1個線程管理)

備註

等待有一個在你的代碼中的漏洞:

int recvbuflen = DEFAULT_BUFLEN; 

那你就用這個進入接收..它是不好的,這可能會產生溢出,爲了解決這個問題,聲明你緩衝區爲: char recvbuf [DEFAULT_BUFLEN + 1];

+0

我該如何「將它貼入新線程」?就是那個問題。 – check123 2011-03-14 12:32:42

+0

我試圖查找示例,但找不到任何有用的示例。 – check123 2011-03-14 12:33:46

+0

我更新了我的答案。請記住,在進入多線程服務器編程之前,您至少要了解線程以及如何使用它們。 – CoolStraw 2011-03-14 12:36:31