Simple webserver won't work

折月煮酒 提交于 2019-12-25 16:38:14

问题


I'm trying to write a webserver in C. I know I could use many different libraries for that, but I want it to run only with winsock. The server and a client can send data back and forth but loading the webpage is impossible. Every time I get a 'server unreachable' message, but on the server I get the message that the body was sent. What am I doing wrong?

edit I'm using chrome and 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();
}

回答1:


This function:

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

reads nothing letting all in the buffer until the client (the browser) reset the connection. If you check the value returned by send(csock, response, strlen(response), 0); you'll see a SOCKET_ERROR. Calling WSAGetLastError() will return

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

The way you use to read socket is really ugly! Use ioctlsocket() with FIONREAD to obtain the number of chars to read:

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;
}

To use it fix your source:

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();
}


来源:https://stackoverflow.com/questions/31765278/simple-webserver-wont-work

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!