2010-09-08 120 views
2

我是套接字編程的初學者。我目前正在嘗試開發一個Web服務器,它可以爲瀏覽器提供基本的GET和POST HTTP請求。我正在使用我的筆記本電腦作爲服務器和客戶端。所以我的想法是,我應該能夠在Firefox中鍵入http://127.0.0.1:PORT/,並且我的Web服務器應該能夠連接到該端口並開始通話。C中的套接字編程 - 網絡服務器

到目前爲止,我寫的代碼似乎沒有工作。我使用ConText和Cygwin能夠在Windows中運行和執行程序。我已經從我使用的端口中刪除了防火牆。但是,網絡服務器似乎無法識別連接。

任何想法爲什麼?我附上我迄今爲止編寫的代碼。任何幫助將非常感激。目前該節目不會過去「聽港口」。我已經孤立了這個錯誤,似乎它卡住了我強調的陳述。

/* Webserver Code */ 

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netdb.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <arpa/inet.h>    // for the use of inet_ntop() 
#include <netinet/in.h> 

#define PORT "1500"    // the port we will connect to 
#define BACKLOG 10     // how many pending connections the queue will hold 

void *get_in_addr(struct sockaddr *sa); 


int main (void) { 

    int sockfd, new_fd=0; 
    int status; 
    struct addrinfo hints; 
    struct addrinfo *servinfo;  
    struct sockaddr_storage their_addr; 
    char s[INET6_ADDRSTRLEN]; 
    socklen_t addr_size;    

    FILE *errors; 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC;  
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE;  


    errors = fopen("Errors.txt", "w"); 
     fprintf(errors,"testing...\n"); 
    if(errors == NULL){ 
     fprintf(stderr, "Cant open output file\n"); 
    } 
    if ((status = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) { 
     fprintf(errors, "getaddrinfo error: %s\n", gai_strerror(status)); 
     exit(1); 
    } 

    // make a socket 
    // socket() function returns a socket file descriptor called sockfd 
    sockfd = socket(servinfo->ai_family, servinfo->ai_socktype, 0); 

    // bind to the port we passed in to getaddrinfo() 
    if((bind(sockfd, servinfo->ai_addr, servinfo->ai_addrlen))== -1) { 
     fprintf(errors, "Binding Failed\n"); 
     exit(1); 
    }         

    // listen on the port 
    if((listen(sockfd, BACKLOG))== -1) { 
     fprintf(errors, "Listening failed\n"); 
     exit(1); 
    } else { 
     printf("Listening on port...\n"); 
} 

    //now accept an incoming connection 
    addr_size = sizeof(their_addr); 
    **new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size)**; 
printf("new_fd = %d\n", new_fd); 
    if(new_fd == -1) { 
     fprintf(errors, "Accepting failed\n"); 
     exit(1); 
} else { 
    printf("The Accepting worked\n"); 
} 

    //Prints out the address of the connector 
    inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof(s)); 
    printf("server: got connection from %s\n", s); 
    fclose(errors); 

return 0; 
} 



// To obtain the client's information 
void *get_in_addr(struct sockaddr *sa) 
{ 
    if (sa->sa_family == AF_INET) { 
     return &(((struct sockaddr_in*)sa)->sin_addr); 
    } 

    return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 

回答

2

getaddrinfo()可能返回多個條目,包含IPv6的。這可能是你的問題。

N.B. getaddrinfo()呼叫後錯誤檢查丟失。

如果你想瀏覽器能夠連接到「127.0.0.1:PORT」,你應該:

  • bind()到INADDR_LOOPBACK和端口,而不從getaddrinfo()
  • 正確設置調用任何幫助到getaddrinfo(),設置ai_familyAF_INET(這樣你只有IPv4)。

注意的是如果getaddrinfo()第一個參數是NULL,則返回地址將被設置爲INADDR_ANY/IN6ADDR_ANY,這意味着你的服務器也會從外部接受連接。要限制連接到本地主機,請將第一個參數設置爲「localhost」而不是NULL。


爲了延續這一塊,在這裏不用我getaddrinfo()結果自卸車代碼:

struct addrinfo hints, *aires=0, *ai; 
    int i; 
    int rc; 

    memset(&hints, 0, sizeof(hints)); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; 
    rc = getaddrinfo("localhost", "1500", &hints, &aires); 
    if (rc == 0) { 
     for (ai=aires, i=0; ai; ai=ai->ai_next, i++) { 
      printf("gai: ai[%d].ai_canonname = %s\n", i, ai->ai_canonname); 
      printf("gai: ai[%d].ai_flags  = %d\n", i, ai->ai_flags); 
      printf("gai: ai[%d].ai_family = %d (%s)\n", i, ai->ai_family, get_family_name(ai->ai_family)); 
      printf("gai: ai[%d].ai_socktype = %d\n", i, ai->ai_socktype); 
      printf("gai: ai[%d].ai_protocol = %d (%s)\n", i, ai->ai_protocol, get_proto_name(ai->ai_protocol)); 
      printf("gai: ai[%d].ai_addrlen = %d\n", i, (int)ai->ai_addrlen); 

      if (ai->ai_family == AF_INET) { 
       struct sockaddr_in *sa = (struct sockaddr_in *)ai->ai_addr; 
       printf("gai: ai[%d].ai_addr[IPv4].sin_family = %d (%s)\n", i, sa->sin_family, get_family_name(sa->sin_family)); 
       printf("gai: ai[%d].ai_addr[IPv4].sin_port = %d\n", i, ntohs(sa->sin_port)); 
       printf("gai: ai[%d].ai_addr[IPv4].sin_addr = %s\n", 
        i, inet_ntop(AF_INET, &sa->sin_addr, buf, sizeof(buf))); 
      } else if (ai->ai_family == AF_INET6) { 
       struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ai->ai_addr; 
       printf("gai: ai[%d].ai_addr[IPv6].sin6_family = %d (%s)\n", i, sa->sin6_family, get_family_name(sa->sin6_family)); 
       printf("gai: ai[%d].ai_addr[IPv6].sin6_port  = %d\n", i, ntohs(sa->sin6_port)); 
       printf("gai: ai[%d].ai_addr[IPv6].sin6_flowinfo = %d\n", i, sa->sin6_flowinfo); 

       printf("gai: ai[%d].ai_addr[IPv6].sin6_addr  = %s\n", 
        i, inet_ntop(AF_INET6, &sa->sin6_addr, buf, sizeof(buf))); 

       printf("gai: ai[%d].ai_addr[IPv6].sin6_scope_id = %d\n", i, sa->sin6_scope_id); 
      } else { 
       printf("gai: ai[%d].ai_addr = %p\n", i, ai->ai_addr); 
      } 
      printf("\n"); 
     } 
    } else { 
     printf("gai: failed (%d)\n", rc); 
    } 
    freeaddrinfo(aires); 
+0

感謝您的!我做了你所建議的改變,它起作用=)。現在來解決解釋GET消息的問題。謝謝你的幫助。 – BAkz 2010-09-08 11:36:47

+0

個人經驗暗示:您可以忽略HTTP標頭中的所有內容,最多兩行。爲RFC822/RFC2822消息實現功能完整的解析器相當麻煩 - 您可以推遲它。 – Dummy00001 2010-09-08 11:58:21

+0

是的,我知道你的意思。我很困惑= s – BAkz 2010-09-09 01:02:06