0

次のコード行では、リクエスト行 (GETまたはHEAD <filename> HTTP/1.0) を取得して、ファイルに関する情報を取得しています。

これは、html/text ファイルと image/gif ファイルに対して正しく機能しています。

しかし、ディレクトリを に入れると、プログラムはそれがソケットまたは不明であると通知しますが、ディレクトリであると通知するはずです。

UNIXmanの例からコードをコピーしたため、奇妙に思えます。コードの例でmanは、ディレクトリを引数として指定すると、ディレクトリが認識されます。

唯一の違いは、プログラムが実行中にユーザー入力 (クライアントサーバー) からファイル (またはディレクトリ) 名を取得するのに対し、UNIX プログラムはコマンドライン引数から名前を取得することです。

何が問題ですか?

class request {
    vector<string> requests;
    string message;
    bool valid, isGET, isHEAD;
    public:


    explicit request(char line[]): requests(split_string(line)), valid(true) {

        struct stat sb;
        if(stat(requests[1].c_str(), &sb) == -1) {
            cerr << "Usage: GET or HEAD (filename) HTTP/1.0" << endl;
            valid = false;
            exit(EXIT_FAILURE);
        }

        string cont_type = "Content-Type: ";

        switch (sb.st_mode & S_IFMT) {
            case S_IFBLK:  printf("block device\n");            break;
            case S_IFCHR:  printf("character device\n");        break;
            case S_IFDIR:  cont_type += "directory\n"; cout << "DIRECTORY" <<endl;          break;
            case S_IFIFO:  printf("FIFO/pipe\n");               break;
            case S_IFLNK:  printf("symlink\n");                 break;
            case S_IFREG:  {
                string ext = requests[1].substr(requests[1].size()-6, 6);
                if(ext.find(".html") != string::npos || ext.find(".txt") != string::npos) {cont_type += "text/html file\n";}
                else if(ext.find(".jpg") != string::npos || ext.find(".jpeg") != string::npos || ext.find(".gif") != string::npos || ext.find(".png") != string::npos) {cont_type += "image/gif file\n";}
                else {cont_type += "regular file\n";}
                                                                break;
            }
            case S_IFSOCK: printf("socket\n");                  break;
            default:       printf("unknown?\n");                break;
        }
    }

念のため、次を使用して接続できるサーバーであるコード全体を追加しますtelnet localhost 8080

#define BUF_LEN 8192

#include<queue>
#include<sstream>
#include<vector>
#include<string>
#include<iostream>
#include<cstring>
#include<cstdlib>
 extern "C" {
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<netdb.h>
#include<unistd.h>
#include<stdio.h>
#include<sys/time.h>
}

using std::vector;
using std::string;
using std::cerr;
using std::cout;
using std::endl;
using std::stringstream;
using std::queue;
using std::priority_queue;

char* time_stamp();

class request {
    vector<string> requests;
    string message;
    off_t filesize;
    bool valid, isGET, isHEAD;
    public:
    request() : valid(true) {}

    explicit request(char line[]): requests(split_string(line)), valid(true) {
        if(requests[0] == "GET") isGET = true;
        else if(requests[0] == "HEAD") isHEAD = true;
        else {
            cerr << "Usage: GET or HEAD (filename) HTTP/1.0" << endl;
        }

        //chdir();

        struct stat sb;
        if(stat(requests[1].c_str(), &sb) == -1) {
            cerr << "Usage: GET or HEAD (filename) HTTP/1.0" << endl;
            valid = false;
//            exit(EXIT_FAILURE);
        }

        filesize = sb.st_size;
        string lmstring(ctime(&sb.st_mtime));
        string lm = "Last-Modified: " + lmstring;

        string cont_type = "Content-Type: ";

        switch (sb.st_mode & S_IFMT) {
            case S_IFBLK:  cout << "block device" << endl;       break; 
            case S_IFCHR:  cout << "character device" << endl;   break; 
            case S_IFDIR:  cont_type += "directory\n"; cout << "DIRECTORY" <<endl;          break; 
            case S_IFIFO:  cout << "FIFO/pipe" << endl;          break; 
            case S_IFLNK:  cout << "symlink" << endl;            break; 
            case S_IFREG:  {
                string ext = requests[1].substr(requests[1].size()-6, 6);
                if(ext.find(".html") != string::npos || ext.find(".txt") != string::npos) {cont_type += "text/html file\n";}
                else if(ext.find(".jpg") != string::npos || ext.find(".jpeg") != string::npos || ext.find(".gif") != string::npos || ext.find(".png") != string::npos) {cont_type += "image/gif file\n";}
                else {cont_type += "regular file\n";}
                                                                break;
            } 
            case S_IFSOCK: cout << "socket" << endl;            break; 
            default:       cout << "unknown?" << endl;          break; 
        }

        stringstream cl_ss;
        cl_ss << "Content-Length: " << sb.st_size << '\n';
        string cont_len = cl_ss.str();
        message = lm + cont_type + cont_len;

        FILE * pFile;
        long lSize;
        char * buffer;
        size_t result;
/*
        if(isGET) {
            pFile = fopen ( requests[1].c_str() , "r" );
            if (pFile==NULL) {fputs ("File error",stderr); exit (1);}

            // obtain file size:
            fseek (pFile , 0 , SEEK_END);
            lSize = ftell (pFile);
            rewind (pFile);

            // allocate memory to contain the whole file:
            buffer = (char*) malloc (sizeof(char)*lSize);
            if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}

            // copy the file into the buffer:
            result = fread (buffer,1,lSize,pFile);
            if (result != lSize) {fputs ("Reading error",stderr); exit (3);}

            // the whole file is now loaded in the memory buffer.

            // terminate
            fclose (pFile);
            free (buffer);
        }
        cout << buffer << endl;*/
    }

    bool operator<(const request& rhs) const{
        return filesize < rhs.filesize;
    }

    string getMessage() const {
        return this->message;
    }

    vector<string> split_string(char line[]) {
        vector<string> vec_str;
        char* token;
        token = strtok(line, " ");

        while (token != NULL) {
            string temp_str(token);
            vec_str.push_back(temp_str);
            token = strtok(NULL, " ");
        }
        return vec_str;
    }
};

int main() {

    int status;
    struct addrinfo host_info; // The struct that getaddrinfo() fills up with data.
    struct addrinfo *host_info_list; // Pointer to the linked list of host_info's.

    // The MAN page of getaddrinfo() states "All the other fields in the structure pointed
    // to by hints must contain either 0 or a null pointer, as appropriate." When a struct
    // is created in C++, it will be given a block of memory. This memory is not necessarily
    // empty. Therefore we use the memset function to make sure all fields are NULL.
    memset(&host_info, 0, sizeof host_info);

    std::cout << "Setting up the structs..." << std::endl;

    host_info.ai_family = AF_UNSPEC;     // IP version not specified. Can be both.
    host_info.ai_socktype = SOCK_STREAM; // Use SOCK_STREAM for TCP or SOCK_DGRAM for UDP.
    host_info.ai_flags = AI_PASSIVE;     // IP Wildcard

    // Now fill up the linked list of host_info struts with ???????????????
    status = getaddrinfo(NULL, "8080", &host_info, &host_info_list);

    // getaddrinfo returns 0 on success, or some other value when an error occurred.

    if (status != 0) std::cout << "getaddrinfo error" << gai_strerror(status);

    std::cout << "Creating a socket..." << std::endl;
    int socketfd; // The socket descripter
    socketfd = socket(host_info_list->ai_family, host_info_list->ai_socktype, host_info_list->ai_protocol);

    if(socketfd == -1)  std::cout << "socket error " << std::endl;

    std::cout << "Binding socket..." << std::endl;

    // we use to make the setsockopt() function to make sure the port is not in use
    // by a previous execution of our code.

    int yes = 1;
    status = setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
    status = bind(socketfd, host_info_list->ai_addr, host_info_list->ai_addrlen);
    if (status == -1)  std::cout << "bind error" << std::endl;

    std::cout << "Listen()ing for connections..." << std::endl;
    status = listen(socketfd, 5);
    if (status == -1)  std::cout << "listen error" << std::endl;

    int new_sd;
    struct sockaddr_storage their_addr;
    socklen_t addr_size = sizeof(their_addr);
    new_sd = accept(socketfd, (struct sockaddr *)&their_addr, &addr_size);

    if (new_sd == -1) {
        std::cout << "listen error" << std::endl;
    }
    else {
        std::cout << "Connection accepted. Using new socketfd : " << new_sd << std::endl;
    }





    // after success on listen()ing, loop waiting
    int done;
    ssize_t bytes_received;
    char buf[BUF_LEN];
    fd_set ready;

    while (!done) {

/* fd_set contains the following fields:

 typedef struct fd_set {
        u_int   fd_count;               //how many are SET?
        SOCKET  fd_array[FD_SETSIZE];   //an array of SOCKETs
} fd_set;
*/


    FD_ZERO(&ready);
    FD_SET(new_sd, &ready);
    FD_SET(fileno(stdin), &ready);

    if (select((new_sd + 1), &ready, 0, 0, 0) < 0) {
        cerr << "Error from select" << endl;
        std::exit(1);
    }

    if (FD_ISSET(fileno(stdin), &ready)) {
        if((bytes_received = read(fileno(stdin), buf, BUF_LEN)) <= 0)
            done++;
        send(new_sd, buf, bytes_received, 0);
    }

    std::cout << "Waiting to receive data..." << std::endl;
    bytes_received = recv(new_sd, buf, BUF_LEN, 0); // recv or recvfrom???

    // If no data arrives, the program will just wait here until some data arrives.

    if (bytes_received == 0) std::cout << "host shut down." << std::endl;
    if (bytes_received == -1) std::cout << "receive error!" << std::endl;
    std::cout << bytes_received << " bytes received: " << std::endl;
    buf[bytes_received] = '\0';
    std::cout << "elements of 'buf'" << buf << std::endl;


    std::cout << "Send()ing back a message..." << std::endl;

    request tobeadded(buf);
    request rq;
    if(true) {
        queue<request> qr;
        qr.push(tobeadded);
        rq = qr.front();
        qr.pop();
    }
    else {
        priority_queue<request> pqr;
        pqr.push(tobeadded);
        rq = pqr.top();
        pqr.pop();
    }

    string timeheader = "Time: ";
    const char* t_h = timeheader.c_str();
    char* timestamp = time_stamp();
    string server = "Server: myhttp\n";
    const char* serv = server.c_str();

    const char* lm_ct_cl = rq.getMessage().c_str();

    char *msg = new char[strlen(t_h) + strlen(timestamp) + strlen(serv) + strlen(lm_ct_cl) + 1];

    *msg = '\0';
    strcat(msg, t_h);
    strcat(msg, timestamp);
    strcat(msg, serv);
    strcat(msg, lm_ct_cl);

    int len;
    ssize_t bytes_sent;
    len = strlen(msg);
    bytes_sent = send(new_sd, msg, len, 0);

    //write(fileno(stdout), buf, bytes_received);
    }

    std::cout << "Stopping server..." << std::endl;
    freeaddrinfo(host_info_list);
    close(new_sd);
    close(socketfd);

return 0;
}

char* time_stamp() {
    time_t current_time;
    char* c_time_string;

    /* Obtain current time as seconds elapsed since the Epoch. */
    current_time = time(NULL);

    if (current_time == ((time_t)-1))
    {
        (void) fprintf(stderr, "Failure to compute the current time.");
    }

    /* Convert to local time format. */
    c_time_string = asctime(gmtime(&current_time));

    if (c_time_string == NULL)
    {
        (void) fprintf(stderr, "Failure to convert the current time.");
    }

    c_time_string[strlen(c_time_string)-1] = ' ';

    return strcat(c_time_string, " GMT\n");
}
4

0 に答える 0