对http://tuoxie174.blog.51cto.com/1446064/413189 的源代码分析

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
using namespace std;

#define PORT        8848  //Port
#define BACKLOG     5     // Max Link num
#define MAXDATASIZE 1000  // Max data buf
#define DEBUG 1

//1. Func Decalare
void process_cli(int connectfd, sockaddr_in client);
int  sendobj(int connectfd, char* serverfilepath);
int  isDIR(char* path);
int  fileordirExist(char* fpath);
char* gettextname(char*);
int   writehead(FILE* cfp, char* extname);
void* start_routing(void* arg);
void  msg404(int connectfd);

//2. Structure Decalare
struct ARG
{
    int         connfd;
    sockaddr_in client;
};


int main()
{
    //cout << "Hello world!" << endl;
    int listenfd, connectfd;
    //! 1. thread id
    pthread_t thread;
    //! 2. pass this var to the thread
    ARG*      arg;
    struct sockaddr_in server;
    struct sockaddr_in client;
    int    sin_size;

    //! 3. create tcp socket
#ifdef DEBUG
    printf("socket...\n");
#endif
    if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1)
    {
        perror("creating socket failed!\n");
        exit(1);
    }
    //! 4. set the socket -- close, timeout
    int opt = SO_REUSEADDR;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    bzero(&server, sizeof(server));

    server.sin_family = AF_INET;
    server.sin_port   = htons(PORT);
    server.sin_addr.s_addr = htonl(INADDR_ANY);

    printf("bind...\n");
    //! 5. bind a ip and port to the socket
    if(bind(listenfd, (struct sockaddr*)&server, sizeof(struct sockaddr)))
    {
        perror("bind error!");
        exit(1);
    }

    printf("listen...\n");
    //! 6. listen the socket
    if(listen(listenfd,BACKLOG)==-1)
    {
        perror("listen error!\n");
        exit(1);
    }

    // a datastructure for programmer to use struct sockaddr
    sin_size = sizeof(struct sockaddr_in);
    while(1)
    {
        // begin to process the client's connect
        //! 7. accept using main thread
        printf("accepting...\n");

        if((connectfd=accept(listenfd, (struct sockaddr*)&client, (socklen_t*)&sin_size))==-1)
        {
            printf("accept error!\n");
        }

        //connectfd is a socket
        arg = new ARG;
        arg->connfd = connectfd;
        memcpy((void*)&arg->client, &client, sizeof(client));

         #ifdef DEBUG
            printf("thread creating...\n");
         #endif
        //! 8. invoke start_routing to handle this thread. -- start_routing is a callback func
        if(pthread_create(&thread, NULL, start_routing, (void*)arg))
        {
            perror("pthread_create error!\n");
            exit(1);
        }

    }
    close(listenfd);

    return 0;
}

//! 1.1 handle the request
void process_cli(int connectfd, sockaddr_in client)
{
    int  num;
    char requestline[MAXDATASIZE];
    char filepath[MAXDATASIZE];
    char cmd[MAXDATASIZE];
    char extname[MAXDATASIZE];

    int c;
    FILE *fp;
    //! Because everything is file in UNIX
    //! 1.1.1 open the client socket
    fp = fdopen(connectfd, "r");

#ifdef DEBUG
    printf("the host is: %s \n", inet_ntoa(client.sin_addr));
#endif
    fgets(requestline, MAXDATASIZE, fp);

#ifdef DEBUG
    printf("The request is: %s \n", requestline);
#endif

    strcpy(filepath, "./");
    sscanf(requestline, "%s%s\n", cmd, filepath+2);
    //! use func gettextname
    strcpy(extname, gettextname(filepath));

#ifdef DEBUG
    printf("cmd: %s\n filepath: %s\n extname: %s\n", cmd, filepath, extname);
    printf("string comparing\n:::::::start:::::::\n");
#endif

    if(strcmp(cmd, "GET")==0)
    {
#ifdef DEBUG
        printf("cmd(%s)==GET\n", cmd);
#endif

        if(fileordirExist(filepath))
        {
            if(isDIR(filepath))
            {
                //! is a DIR
#ifdef DEBUG
                printf("%s is a DIR \n", filepath);
#endif
                if(fileordirExist(strcat(filepath, "index.html")))
                {
                    //! send
                    sendobj(connectfd, "index.html");
                }
                else
                {
                    msg404(connectfd);
                }
            }
            else
            {
                //! is a file
#ifdef DEBUG
                printf("%s is a file \n", filepath);
#endif
                //! send
                sendobj(connectfd, filepath);
            }
        }
        else
        {
#ifdef DEBUG
            printf("404\n");
#endif
            msg404(connectfd);
        }
    }
    else
    {
#ifdef DEBUG
        printf("cmd(%s)!=GET\n", cmd);
#endif
    }
#ifdef DEBUG
    printf("::::::::::::::::::::end::::::::::::::::::\n");
    close(connectfd);
#endif
}

//! 1.2
void msg404(int connectfd)
{
    char* msg;
    msg = "HTTP/1.0 404 Not Found Content-Type: text/plain 404 not found by Manio\n";
    send(connectfd, msg, strlen(msg), 0);
}

//! 1.3 is the filepath a file or direatory
int fileordirExist(char* fpath)
{
    struct stat filestat;
    return ( stat(fpath, &filestat)!=-1);
}

//! 1.4 is the filepath a directory
int isDIR(char* fpath)
{
#ifdef DEBUG
    printf("IN IsDir\ns");
#endif
    struct stat filestat;
    return ( stat(fpath, &filestat)!=-1 && S_ISDIR(filestat.st_mode));
}

//! 1.5 send the data of the file which the client want
int sendobj(int connectfd, char* serverfilepath)
{
    //printf("server: %s\n", serverfilepath)
    FILE* sfp=NULL, *cfp=NULL;
    char c;
    sfp = fopen(serverfilepath, "r");
    cfp = fdopen(connectfd, "w");

    if(sfp == NULL)
      printf("can't open the file!... \n");
    if(cfp == NULL)
      printf("can't open the link file...!\n");

    writehead(cfp, gettextname(serverfilepath));

    while( (c=getc(sfp)) !=EOF){
        putc(c, cfp);
        //putchar(c);
    }
    fflush(cfp);
    return 0;
}

//! 1.6 write the packet header to the client
int writehead(FILE* cfp, char* extname)
{
#ifdef DEBUG
    printf("INWRITEHEAD:::::extname is %s::::::\n", extname);
#endif
    char* content = "text/plain";
    if(strcmp(extname, "html")==0 || strcmp(extname, "htm")==0)
        content = "text/html";
    else if(strcmp(extname,"css")==0)
        content = "text/css";
    else if(strcmp(extname,"gif")==0)
        content = "p_w_picpath/gif";
    else if(strcmp(extname,"jpeg")==0||strcmp(extname,"jpg")==0)
        content = "p_w_picpath/jpeg";
    else if(strcmp(extname, "png")==0)
        content = "p_w_picpath/png";

#ifdef DEBUG
    printf("HTTP/1.1 200 OK\n");
    printf("Content-Type: %s \n", content);
#endif

    fprintf(cfp, "HTTP/1.1 200 OK ");
    fprintf(cfp, "Content-Type: %s \n", content);

    return 0;
}

//! 1.7 get the extent name of the file
char* gettextname(char* filepath)
{
    char* p;
    if((p=strrchr(filepath,'.'))!=NULL)
        return p+1;
    return NULL;
}

//! 1.8 invoked by pthread_create
void* start_routing(void* arg)
{
    ARG* info;
    info = (ARG*) arg;
    // handle client's requirement
    process_cli(info->connfd, info->client);
    delete arg;
    pthread_exit(NULL);
}

//1.  只要 g++ -g -o execname filename -lpthread

//2. 然后在浏览器输入: 127.0.0.1:8848

//3. 与程序同目录下 有 index.html (注意扩展名, 程序中为判断)

问题: 中文会出现乱码, 查看源代码, 发现<head> 的很大一部分没有了, 只留下后面的, 于是乎编码没有设置。 (英文网页时,前半部分也没了)。 继续解决。