简单的网络服务器将无法工作

Simple webserver won't work

我正在尝试用 C 编写一个网络服务器。我知道我可以为此使用许多不同的库,但我希望它 运行 仅与 winsock 一起使用。服务器和客户端可以来回发送数据,但无法加载网页。每次我收到 'server unreachable' 消息,但在服务器上我收到正文已发送的消息。我做错了什么?

编辑 我正在使用 chrome 和 Microsoft Edge

#include <stdio.h>
#include <conio.h>

#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib")

void error(const char* err){
    printf("ERROR: %s\n", err);
    exit(1);
}

char* readline(SOCKET s){
    FILE * f = tmpfile();
    char rec;
    int i=0;
    while(recv(s, &rec, 1, 0)>0){
        i++;
        if(rec!='\r' && rec!='\n')
            fwrite(&rec, 1, 1, f);
        if(rec=='\r' || rec=='\n')
            break;
    }
    if(i==0){
        fclose(f);
        return NULL;
    }
    fseek(f, 0, SEEK_END);
    long long size = ftell(f);
    fseek(f, 0, SEEK_SET);
    char * d = (char*) malloc(size);
    memset (d,0,size);
    fread(d, 1, size, f);
    fclose(f);
    return d;
}

void flush(SOCKET s){
    while(recv(s, NULL, 1, 0)>0){
    }
}

void main(){

    // CREATE SERVER
    WSADATA wsa;
    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
        error("WSAStartup");
    SOCKET s;
    if((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
        error("socket");
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(80);
    if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
        error("bind");

    // SERVER CREATED
    while(1){
        listen(s, 1);
        int c = sizeof(struct sockaddr_in);
        SOCKET csock;
        struct sockaddr_in client;
        if((csock = accept(s, (struct sockaddr*)&client, &c))==INVALID_SOCKET)
            continue;
        char *client_ip = inet_ntoa(client.sin_addr);
        printf("Incomming connection: %s\n", client_ip);

        char * head = readline(csock);
        if(strncmp(head, "GET", 3)==0){
            flush(csock);

            char response[] = "HTTP/1.1 200 OK\r\n"
            "Content-Type: text/html\r\n\r\n"
            "<html><head><title>test</title>"
            "</head><body>Test123</body></html>";
            send(csock, response, strlen(response), 0);
            printf("%s\n", "HTML body sended");
        }else if(strncmp(head, "HEAD", 4)==0){
            flush(csock);

            char response[] = "HTTP/1.1 200 OK\r\n"
            "Content-Type: text/html\r\n\r\n";
            send(csock, response, strlen(response), 0);
            printf("%s\n", "HTML head sended");
        }

        closesocket(csock);
    }

    closesocket(s);
    WSACleanup();
}

这个函数:

void flush(SOCKET s){
    while(recv(s, NULL, 1, 0)>0){
    }
}

在客户端(浏览器)重置连接之前,什么都不读取,让缓冲区中的所有内容。 如果您检查由 send(csock, response, strlen(response), 0); 编辑的值 return,您将看到 SOCKET_ERROR。调用 WSAGetLastError() 将 return

Code 0x2745 = An established connection was aborted by the software in your host machine.

你读socket的方式真丑!使用 ioctlsocket()FIONREAD 来获取要读取的字符数:

char* readline(SOCKET s)
{
    size_t MsgLen = 0;
    char *Msg = NULL;
    unsigned long Len;
    int res;
    while (0 == (res=ioctlsocket(s, FIONREAD, &Len)))
    {
        if (SOCKET_ERROR == Len)
        {
            if (Msg)
            {
                free(Msg);
                Msg = NULL;
            }
            return NULL;
        }

        if (!Len && MsgLen)
            break;

        if (!Msg)
            Msg = malloc(Len);
        else
            Msg = realloc(Msg, MsgLen + Len);

        recv(s, Msg+MsgLen, Len, 0);

        MsgLen += Len;
    }
    return Msg;
}

要使用它修复您的来源:

char response[] = "HTTP/1.1 200 OK\r\n"
                  "Content-Type: text/html\r\n\r\n"
                  "<html><head><title>test</title>"
                  "</head><body>Test123</body></html>\r\n";

char response[] = "HTTP/1.1 200 OK\r\n"
                  "Content-Type: text/html\r\n\r\n";

int main(int argc, char *argv[])
{

    // CREATE SERVER
    WSADATA wsa;
    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
        error("WSAStartup");
    SOCKET s;
    if((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
        error("socket");
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(80);
    if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
        error("bind");

    // SERVER CREATED
    while(1){
        listen(s, 1);
        int c = sizeof(struct sockaddr_in);
        SOCKET csock;
        struct sockaddr_in client;
        if((csock = accept(s, (struct sockaddr*)&client, &c))==INVALID_SOCKET)
            continue;
        char *client_ip = inet_ntoa(client.sin_addr);
        printf("Incoming connection: %s\n", client_ip);

        char * head = NULL;
        do
        {
            head = readline(csock);
        } while (!head);
        if(strncmp(head, "GET", 3)==0)
        {
            if (SOCKET_ERROR  == send(csock, response, strlen(response), 0))
            {
                WSAGetLastError();
            }
            printf("%s\n", "HTML body sended");
        }
        else
            if(strncmp(head, "HEAD", 4)==0)
            {
                send(csock, response, strlen(response), 0);
                printf("%s\n", "HTML head sended");
            }

        closesocket(csock);
    }

    closesocket(s);
    WSACleanup();
}