2012-10-22 2 views
-2

프록시 서버를 구축 중이며 select() 함수를 이해하려고합니다. 코드가 완료되어 클라이언트에서 연결이 만들어진 다음 웹 주소가 추출되어 다른 연결을 통해 실제 웹 서버에 연결할 수 있습니다. 페이지는 프록시에 의해 수신되고 클라이언트로 다시 전달됩니다.select() 프록시 서버에서

select()은 여러 클라이언트 요청을 처리 할 수 ​​있지만 웹 서버에 대한 두 번째 연결이 어떻게 도움이되는지 (또는 구현 방법이) 이해되지 않습니다. 나는 웹 서버로부터 데이터를 받아 클라이언트로 다시 전달하기 위해 더 이상 while 루프가 필요 없다는 것을 알고 있습니다.

웹 서버 연결에 대해 두 번째 파일 설명자 세트가 필요합니까? 두 개 이상의 클라이언트 요청을 처리하는 경우 어떻게 웹 서버에 대한 적절한 연결로 연결되는지 확인해야합니까? 어쨌든, 나는 어떤 도움을 주셔서 감사합니다. 나는 네트워킹 자습서와 몇몇 다른 온라인을 통해 갔다. 그러나 며칠 후 나는 아직도 이것에 대해 내 머리를 싸지 않았다.

void error(const char *msg) 
{ 
    perror(msg); 
    exit(1); 
} 

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

string getHostString(const char *buf); 

int main(int argc, char *argv[]) 
{ 
    int sockfd, newsockfd, portno; 
    int fdmax; //maximum file descriptor number 
    socklen_t clilen; 
    char buffer[256]; 
    struct sockaddr_storage remoteaddr; //client address 
    char clientIP[INET6_ADDRSTRLEN]; 

    //fd_set readfds, writefds, exceptfds; 
    fd_set masterfds, readfds; 
    struct timeval timeout; 
    int rc; 

    /*Set time limit. */ 
    timeout.tv_sec = 3; 
    timeout.tv_usec = 0; 

    /*Create a descriptor set containing the sockets */ 
    FD_ZERO(&readfds); 
    FD_ZERO(&masterfds); 
    /*FD_ZERO(&writefds); 
    FD_ZERO(&exceptfds); 
    FD_SET(newsockfd, &readfds); 

    rc = select(sizeof(readfds)*8, &readfds, NULL, NULL, &timeout); 
    if (rc==-1){ 
     perror("select failed"); 
     return -1; 
    }*/ 

    struct sockaddr_in serv_addr, cli_addr; 
    int n; 
    if (argc < 2) { 
     fprintf(stderr,"ERROR, no port provided\n"); 
     exit(1); 
    } 

    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    if (sockfd < 0) 
     error("ERROR opening socket"); 

    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    portno = atoi(argv[1]); 
    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = INADDR_ANY; 
    serv_addr.sin_port = htons(portno); 

    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
      error("ERROR on binding"); 

    if((listen(sockfd,5)) == -1) 
     error("Server-listen() error!!!"); 
    printf("Server-listen() is OK...\n"); 


    FD_SET(sockfd, &masterfds); 

    //keep track of the biggest file descriptor so far 
    fdmax = sockfd; //so far it's this one 

    for(;;){ 

     readfds = masterfds; 

     if(select(fdmax+1, &readfds, NULL, NULL, NULL) == -1){ 
      error("Server-select() error !"); 
     } 
     printf("Server-select() is OK...\n"); 

     for(int i = 0; i <= fdmax; i++){ 
      printf("i: %d sockfd %d\n", i, sockfd); 
      if(FD_ISSET(i, &readfds)){ 
       if(i == sockfd){ //sockfd is the listener 
        //following handles new connections 
        clilen = sizeof(cli_addr); 
        if((newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen)) == -1) 
         error("Server-accept() error!!!"); 
        else{ 
         printf("Server-accept() is OK...\n"); 
         FD_SET(newsockfd, &masterfds); //add to master set 
         if(newsockfd > fdmax) 
          fdmax = newsockfd; 
         printf("selectserver: New connection from %s on " 
           "socket %d\n", 
           inet_ntop(remoteaddr.ss_family, 
            get_in_addr((struct sockaddr*)&cli_addr), 
            clientIP, INET6_ADDRSTRLEN), 
           newsockfd); 
        } 
       } 
       else{ 
        //handle data from a client 
        //Here is where the FIRST read occurs 
        bzero(buffer,256); 
        //n = read(newsockfd,buffer,255); 
        n = read(i,buffer,255); 
        if (n < 0) error("ERROR reading from socket"); 
        printf("Here is the message: \n\n%s\n\n",buffer); 

        //string hoststring(buffer); 
        string hoststring(getHostString(buffer)); 

        int html_port = 80; 
        int html_socket; 

        printf("Prior to struct addrinfo\n"); 

        struct addrinfo hints, *res; 

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

        printf("Prior to getaddrinfo()\n"); 

        char *address = new char[hoststring.size() +1]; 
        address[hoststring.size()] = 0; 
        memcpy(address, hoststring.c_str(), hoststring.size()); 

        //getaddrinfo(token, (char *)html_port, &hints, &res); 
        getaddrinfo(address, "80", &hints, &res); 

        printf("We are past getaddrinfo()\n"); 

        //if (html_socket = socket(PF_INET, SOCK_STREAM, 0) < 0){ 
        if ((html_socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0){ 
         printf("socket connection error\n"); 
        } 

        printf("We are past socket()\n"); 

        //char* address; 
        //address = new char[256]; 
        //strncpy(address, "www.cs.ucr.edu", sizeof("www.cs.ucr.edu")); 


        printf("address: %s\n", address);  
        struct hostent * host; 
        if ((host = gethostbyname(address)) == NULL){ 
         printf("Problem with gethostbyname()\n"); 
        } 

        printf("We are past gethostbyname() and about to connect.\n"); 

        if (connect(html_socket, res->ai_addr, res->ai_addrlen) < 0) 
         printf("Unsuccessful completion of connect()"); 

        int bytes_sent, bytes_recvd; 
        char recv_buff[1024]; 
        bytes_sent = send(html_socket, buffer, 256, 0); 
        cout << "bytes_sent: " << bytes_sent << endl; 

        //do{ 
         bytes_recvd = recv(html_socket, recv_buff, 1024, 0); 
         cout << "bytes_rcvd: " << bytes_recvd << endl; 
         cout << recv_buff << endl; 

         //FD_ZERO(&readfds); 
         //FD_SET(newsockfd, &writefds); 

         //n = write(newsockfd,"I got your message\n",20); 
         //n = write(newsockfd,recv_buff,bytes_recvd); 
         n = write(i,recv_buff,bytes_recvd); 
         if (n < 0) error("ERROR writing to socket"); 
         bzero(recv_buff, 1024); 
        //}while(bytes_recvd !=0); 
       } 
      } 
     } 

    } 

    close(newsockfd); 
    close(sockfd); 
    return 0; 
} 


string getHostString(const char *buf){ 
    string hoststring(buf); 
    hoststring = hoststring.substr(11); 

    cout << "hoststring: " << hoststring << endl; 
    int slashpos; 
    slashpos = hoststring.find("/"); 
    int suffixendpos = hoststring.find("H") - slashpos; 
    string suffix = hoststring.substr(slashpos, suffixendpos); 
    hoststring = hoststring.substr(0, slashpos); 

    cout << "hoststring: " << hoststring << endl; 
    cout << "suffix: " << suffix << endl; 

    return hoststring; 

} 

답변

0

당신은 select(2)select_tut(2) 맨 페이지를 읽어나요?

예를 들어 관련 장을 읽었습니까? Advanced Linux Programming 또는 Advanced Unix Programming?

사실 때문이 c10k 문제 256 (1024)로 최대 파일 기술자의 한계, 즉 __FD_SETSIZE에)의, select 콜은 폐기되고, 당신은 대신 poll(2) 콜을 사용해야합니다.

당신은 (당신이 전체를 할당 할 수 있도록 fd_set 유형, 배열 될 수있다.) 명시 적 FD_ZEROFD_SET로 바로 select 호출하기 전에, 당신의 for 루프 내부의 readfds을 설정해야합니다. syscall은 select을 수정할 수 있습니다.

gcc -Wall -g으로 컴파일하고 디버거를 사용하는 것을 잊지 마십시오. 기존의 자유 소프트웨어 HTTP 클라이언트 라이브러리 또는 프록시의 소스 코드를 연구 할 수도 있습니다.

1

루프에서 여러 연결을 처리하는 단일 프로세스 서버를 작성하고 select()을 사용하여 소켓 디스크립터에 읽을 데이터가있는시기를 결정하려고합니다. 그러나 때로는 다른 접근법이 실제로는 더 쉽고 확장 성이 좋습니다.

multi-process 서버를 사용하여 각 소켓 연결이 완료된 후 fork() 요청 처리를위한 새로운 프로세스를 고려한 적이 있습니까? 이렇게하면 select()이 작동하고 요청을 올바른 소켓 설명자에 매핑하는 방법에 대해 걱정할 필요가 없습니다.

합당한 예로 Handle Multiple Connections here을 참조하십시오.

fork() 외에도 POSIX pthreads 라이브러리의 스레딩을 사용하면 약간의 효율성을 얻을 수 있습니다. 여기에 a good multi-threaded tcp/ip server sample that uses pthreads.

+0

고마워. 예, 계획은 결국 pthreads를 사용하는 것입니다. 나는 그것을 단순하게 유지하려고 노력했습니다. 방금 select로 구현을 마쳤으므로 이제는 pthread를 사용하도록 수정하려고합니다. – user1354916

관련 문제