2012-11-01 91 views
1

我写了一个小的web服务器,只需要发送一个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); 
} 

,显示了为“服务器:%s的插座上新建连接”唯一的线。

有人可以帮我吗?

亲切的问候,

+0

这就是很多代码 – mathematician1975

+0

我看到'#包括'部分,并认为“啊,这就是为什么!”... ... – 2012-11-01 22:38:36

+1

对不起,大代码。是的,我知道我是一个Windows用户:D。 – user1480139

回答

1

太多的信息在这里的评论 - 但是这可能帮助别人你的问题:

我编译和运行您的代码,当我看到在调试器它是和服务器被阻塞等待输入我觉得

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

控制台

服务器:等待CON nections ... 服务器:从 127.0.0.1插座120服务器上的新连接:从127.0.0.1套接字新建连接124

我缓冲器具有(440个字):

  • 缓冲0x0028f668 “GET/HTTP/1.1 \ r \ n主机:localhost:9001 \ r \ n连接:保持活动\ r \ n用户代理:Mozilla/5.0(Windows NT 6.1; WOW64)AppleWebKit/537.4(KHTML,如Gecko)Chrome/22.0.1229.94 Safari/537.4 \ r \ n接受:text/html,application/xhtml + xml,application/xml; q = 0.9,/; q = 0.8 \ r \ n接受编码:gzip,deflate,sdch \ r \ n接受语言:en-GB,en-US; q = 0.8,en; q = 0.6 \ r \ n接受字符集:ISO-8859-1,utf- 8; q = 0.7,*; q = 0.3 \ r \ nCookie:plushContainerWidth = 100%25; plushNoTopMenu = 0 \ r \ n \ r \nÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ...

和我的浏览器已经等待。

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

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

希望这会有所帮助。