0

我写了一个小网络服务器,它只需要向浏览器发送一个 html 页面或错误页面。只是为了练习我的新套接字知识。

在这个程序中,我试图使用 select 方法来处理超过 1 个请求。

该程序接受了我的连接,但没有任何反应...... firefox 仍在继续加载文件,但该文件从未出现过,并且该程序没有做任何事情(虽然它没有崩溃。)。

这是我的代码:

#include <stdio.h>
#include <winsock2.h>
#include <winsock.h>
#include <Ws2tcpip.h>
#include <time.h>

#pragma comment(lib, "ws2_32.lib" )
#define BUFFSIZE 512
#define PORT "9001"
#define MAXCONNECTIONS 10

char * getPath(char * input, int var, char result[]);
void sendHeader(char * ext, char *path, int socketDescr, int code);
void sendBody(char * ext, char *path, int socketDescr, int code);


int main()
{
    WSADATA wsaData;
    struct timeval tv;  // timeinterval for request (should arrive in less than 2seconds)
    fd_set master;      // keeps track of all open file descriptors + listener
    fd_set read_fds;    // list of file descriptors to read from
    int fdmax;          // max file descriptor number
    int listener;       // file descriptor on socket
    int newfd;          // new client file descriptor
    struct sockaddr_storage clientaddr; // client address
    socklen_t addrlen;  // length of address
    char clientIP[INET_ADDRSTRLEN]; // client ip-address (ipv4)
    char buffer[BUFFSIZE]; // buffer for request
    char request[BUFFSIZE]; // buffer for request
    int recvbytes;      // amount of bytes received
    int yes = 1;        // reuse address
    int i,rv;
    struct addrinfo serverinfo, *socketlist, *sock;

    char result[BUFFSIZE];
    char  * path;
    char * extension;

    if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0) 
    {
        fprintf(stderr, "WSAStartup failed.\n");
        exit(1);
    }

    // Set up time interval
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    // Clean up file descriptor sets
    FD_ZERO(&master);
    FD_ZERO(&read_fds);

    // Get a socket and bind for listening
    memset(&serverinfo, 0, sizeof(serverinfo));
    serverinfo.ai_family = AF_INET;
    serverinfo.ai_socktype = SOCK_STREAM; // TCP
    serverinfo.ai_flags = AI_PASSIVE; // we search a socket on our side (server side) for listening

    if((rv = getaddrinfo(NULL,PORT,&serverinfo,&socketlist)) != 0)
    {
        fprintf(stderr,"Server: %s\n",gai_strerror(rv));
        exit(1);
    }

    // loop trough sockets
    for(sock = socketlist; sock != NULL; sock = sock->ai_next)
    {
        listener = socket(sock->ai_family, sock->ai_socktype, sock->ai_protocol);
        if(listener < 0)
        {
            continue; // not correct socket
        }
        setsockopt(listener,SOL_SOCKET,SO_REUSEADDR, &yes, sizeof(int));
        if(bind(listener, sock->ai_addr, sock->ai_addrlen) < 0)
        {
            closesocket(listener);
            continue; // could not bind to socket
        }
        break;
    }

    // if could not get socket
    if(sock == NULL)
    {
        fprintf(stderr,"Server: %s\n","Could not bind to socket");
        exit(2);
    }

    // free up list, we have the socket
    freeaddrinfo(socketlist);

    // listen on socket
    if(listen(listener,MAXCONNECTIONS) < 0)
    {
        perror("Server: listen");
        exit(3);
    }

    // add listener to master set
    FD_SET(listener,&master);
    fdmax = listener;
    fprintf(stdout,"Server: %s\n","Waiting for connections...");

    for(;;)
    {
        read_fds = master;
        if(select(fdmax+1,&read_fds,NULL,NULL,&tv) < 0)
        {
            perror("Server: select");
            exit(4);
        }

        // run through existing connections to see if request has arrived
        for(i = 0; i <= fdmax; i++)
        {
            if(FD_ISSET(i, &read_fds))
            {
                if(i == listener)
                {
                    // we have a new connection
                    addrlen = sizeof clientaddr;
                    if((newfd = accept(listener,(struct sockaddr*)&clientaddr,&addrlen)) < 0)
                    {
                        perror("Server: accept");
                        exit(5);
                    }
                    else
                    {
                        FD_SET(newfd,&master);
                        if(newfd > fdmax)
                        {
                            fdmax = newfd;
                        }
                        fprintf(stdout, "Server: New connection from %s on socket %d\n",inet_ntop(clientaddr.ss_family, &(((struct sockaddr_in*)((struct sockaddr*)&clientaddr))->sin_addr), clientIP, sizeof(clientIP)),newfd);
                    }
                }
                else
                {
                    // handle data from request
                    if((recvbytes = recv(i,buffer,BUFFSIZE-1,0)) <= 0)
                    {
                        if(recvbytes == 0) //connection closed
                        {
                            fprintf(stdout,"Server: socket %d goodbye\n",i);
                        }
                        else //request error [BAD REQUEST]
                        {
                            perror("Server: recv");
                        }
                        closesocket(i);
                        FD_CLR(i,&master);
                    }
                    else
                    {
                        recvbytes = recv(i, buffer,BUFFSIZE-1 , 0);
                        if(recvbytes > 0)
                        {
                            buffer[recvbytes]='\0';
                            strcat(request,buffer);
                        }
                        fprintf(stdout,"Server: request received:\n");
                        printf("%s", request);

                        //Get path
                        path = getPath(request,0, result);
                        if(strcmp(path,"error") != 0)
                        {
                            extension = getPath(request,1,result);
                            if(strcmp(extension,"error") != 0)
                            {
                                // send file 200
                                sendBody(extension,path,i,200);
                            }
                        }
                        else
                        {
                            // send code 400
                            sendBody("html","400.html",i,400);
                        }

                        closesocket(i);
                        FD_CLR(i,&master);
                    }
                }
            }
        }
    }
    return 0;
}

// Gives path, extension of file or error
char * getPath(char * input, int var, char result [])
{
    char * pch;
    char str[BUFFSIZE];
    strcpy(str,input);

    pch = strtok(str,"\r\n");
    pch = strtok(pch," ");

    if(strcmp(pch,"GET") != 0)
    {
        strcpy(result,"error");
        return result;
    }

    pch = strtok(NULL," ");
    if(var == 0)
    {
        strcpy(result,pch);
        return result; 
    }
    pch = strtok(pch,".");
    pch = strtok(NULL,".");
    if(var == 1)
    {
        strcpy(result,pch);
        return result;
    }

    return 0;
}

//Send header
void sendHeader(char * ext, char *path, int socketDescr, int code)
{
    FILE * fp;
    int fileSize = 0;
    char fileSizeChar[32];
    char * header;
    char * status;
    char * contenType;
    char * contentLength;
    char * msg;

    if((fp = fopen(path, "r")) == NULL)
    {
        printf("Error opening file %s\n",path);
        return;
    }
    //Get filesize
    fseek(fp, 0L, SEEK_END);
    fileSize = ftell(fp);
    fseek(fp, 0L, SEEK_SET);
    fclose(fp);

    //Create header response message
    header = "HTTP/1.0 ";

    if(code == 200)
        strcpy(status,"200");
    else if(code == 400)
        strcpy(status,"400");
    else if(code == 404)
        strcpy(status,"404");

    if(strcmp(ext,"html") == 0)
        strcpy(contenType," text/html\n");

    //create and send header
    strcat(msg,header);
    strcat(msg,status);
    strcat(msg,contenType);
    strcat(msg,contentLength);
    strcat(msg,fileSizeChar);

    send(socketDescr, msg, strlen(msg), 0);
}

//Sending data like, pictures, zip, html pages... or an error html page
void sendBody(char * ext, char *path, int socketDescr, int code)
{
    FILE * fp;
    int fileSize = 0;
    int sendBytes = 0;
    int resultRead;
    int resultSend;
    char buffer[1000];

    if((fp = fopen(path, "r")) == NULL)
    {
        printf("Can't open file %s\n",path);
        if(code == 400)
        {
            printf("Error page 400 doesn't exist.\n");
            return;
        }
        if((fp = fopen("404.html","r")) == NULL)
        {
            printf("Error page 404 doesn't exist.\n");
            return;
        }
        strcpy(ext,"html");
        strcpy(path,"404.html");
        code = 404;
    }

    sendHeader(ext,path,socketDescr,code);

    fseek(fp, 0L, SEEK_END);
    fileSize = ftell(fp);
    fseek(fp, 0L, SEEK_SET);

    while(sendBytes < fileSize)
    {
        fseek(fp,sendBytes,SEEK_SET);
        resultRead = fread(buffer,sizeof buffer[0],1000,fp);
        resultSend = send(socketDescr,buffer,resultRead,NULL);
        sendBytes +=resultSend;
    }
    fclose(fp);
}

显示的唯一行是“ Server: New connection from %s on socket ”。

有人能帮助我吗?

亲切的问候,

4

1 回答 1

1

这里有太多信息需要评论 - 但这可能会帮助其他人解决您的问题:

我编译并运行了你的代码,当我查看调试器时,我认为服务器被阻塞等待输入

                recvbytes = recv(i, buffer,BUFFSIZE-1 , 0);

安慰

服务器:等待连接... 服务器:来自套接字 120 上 127.0.0.1 的新连接 服务器:来自套接字 124 上 127.0.0.1 的新连接

我的缓冲区有(440 个字符):

  • buffer 0x0028f668 "GET / HTTP/1.1\r\nHost: localhost:9001\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9, / ;q=0.8\r\nAccept-Encoding: gzip,deflate,sdch\r \nAccept-Language: en-GB,en-US;q=0.8,en;q=0.6\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r \ ncookie:plushcontainerwidth = 100%25; plushnotopmenu = 0 \ r \ n \ n \ r \ r \ n \ n \ n \ n \nìì确实

我的浏览器等待。

我发送了另一个请求,但它崩溃了 - 所以我怀疑 recv 正在阻塞(查看您可以在通话中使用的选项)可能正在等待一个完整的缓冲区。

此时我在 GetPath 中遇到崩溃,因为请求中没有数据,这是因为 recv 调用返回 0 字节。

希望这可以帮助。

于 2012-11-01T23:33:22.957 回答