• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            興海北路

            ---男兒仗劍自橫行
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統(tǒng)計(jì)

            • 隨筆 - 85
            • 文章 - 0
            • 評(píng)論 - 17
            • 引用 - 0

            常用鏈接

            留言簿(6)

            隨筆分類

            隨筆檔案

            收藏夾

            全是知識(shí)啊

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            一個(gè)多線程web服務(wù)器實(shí)例(C,Linux,詳細(xì)的web服務(wù)器原理)

            系統(tǒng):fedora core 5
            編譯器:g++
            實(shí)現(xiàn)功能:通過http協(xié)議,用瀏覽器查看服務(wù)器上的html,htm,jpg,jpeg,gif,png,css文件 ,或者說查看帶有jpg,jpeg,gif等文件的網(wǎng)頁,即是web~
            把代碼復(fù)制下來到linux里,照著后面的方法編譯、運(yùn)行,就可以看到一個(gè)簡(jiǎn)單的多線程服務(wù)器的效果了。

            原理:
            在瀏覽器中輸入一個(gè)網(wǎng)址,回車之后,瀏覽器會(huì)向相應(yīng)主機(jī)的相應(yīng)端口發(fā)送一段報(bào)文,如果是http協(xié)議的(如平常看到的網(wǎng)頁的傳輸協(xié)議),就會(huì)發(fā)送HTTP請(qǐng)求報(bào)文。下面是一個(gè)報(bào)文的例子:

            GET /index.html HTTP/1.1
            Host: 127.0.0.1:8848
            User-Agent: Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.8.0.1) Gecko/20060313 Fedora/1.5.0.1-9 Firefox/1.5.0.1 pango-text
            Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
            Accept-Language: zh-cn,zh;q=0.5
            Accept-Encoding: gzip,deflate
            Accept-Charset: gb2312,utf-8;q=0.7,*;q=0.7
            Keep-Alive: 300
            Connection: keep-alive

            我們?cè)诜?wù)器端把收到的數(shù)據(jù)打印出來,可以看到瀏覽器發(fā)過來的就是這個(gè)東西。當(dāng)然,也可以用ethereal等抓包工具來抓獲這些報(bào)文。關(guān)于報(bào)文里寫的是什么意思,網(wǎng)上有很多資料的,GOOGLE一下就有了。我們只看第一行。

            GET表示是要從服務(wù)器獲取文件,/index.html是文件的路徑,這個(gè)路徑是相對(duì)于服務(wù)器端程序所在文件夾的路徑。如我的服務(wù)器端程序放在/home/mio/program/webserver1707/里面,那這個(gè)index.html在服務(wù)器上的絕對(duì)路徑就是/home/mio/program/webserver1707/index.html。如果報(bào)文里是GET /admin/login.html HTTP/1.1的話,那么login.html文件在服務(wù)器端的路徑是/home/mio/program/webserver1707/admin/login.html.HTTP/1.1表示的是HTTP協(xié)議的版本是1.1.

            服務(wù)器端程序運(yùn)行后,一直監(jiān)聽8848端品(0-1023的端口由IANA統(tǒng)一分配和控制的,不要用,最好選大一些的端口號(hào)。我原來用了個(gè)1234,用不了,還是選大一點(diǎn)好,可以用5460之類的啊~:) ),當(dāng)監(jiān)聽到客戶端發(fā)來的請(qǐng)求后,就與客戶端建立鏈接,接收客戶端發(fā)過來的請(qǐng)求報(bào)文。我們?nèi)绻堰@些報(bào)文打出來,就可以看到就是與上面請(qǐng)求報(bào)文類似的東西了。

            下面我們要根據(jù)所接受的到的請(qǐng)求報(bào)文(GET /index.html HTTP/1.1)來決定放給客戶端(即瀏覽器)什么東西。這里我們看到瀏覽器要的是index.html這樣一個(gè)html文本,我們就在相應(yīng)路徑(/home/mio/program/webserver1707/index.html)找到這個(gè)文件,不過不要急著發(fā)給客戶端,我們要先告訴客戶端,發(fā)過去的是一個(gè)html文件,讓瀏覽器做好相應(yīng)的準(zhǔn)備。怎么讓瀏覽器知道呢?我們還是用報(bào)文,這個(gè)報(bào)文叫響應(yīng)報(bào)文。報(bào)文由狀態(tài)行、首部行、實(shí)體主體三部分組成。狀態(tài)行只有一行,它和首部行、首部行的每行之間是沒有空行的,但是首部行與實(shí)體主體之間有一個(gè)空行,表明從這個(gè)空行開始,就是你瀏覽器要的數(shù)據(jù)了。下面是一個(gè)用ethereal抓到的響應(yīng)報(bào)文: 

            HTTP/1.1 200 OK
            Cache-Control: private
            Content-Type: text/html; charset=UTF-8
            Content-Encoding: gzip
            Server: GWS/2.1
            Content-Length: 1851
            Date: Sat, 14 Oct 2006 11:33:39 GMT

            <html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>Google</title><style><!--
            body,td,a,p,.h{font-family:arial,sans-serif}
            .h{font-size:20px}
            .q{color:#00c}
            --></style>
            <script>
            <!--
            function sf(){document.f.q.focus();}
            function clk(url,oi,cad,ct,cd,sg){if(document.images){var e = window.encodeURIComponent ? encodeURIComponent : escape;var u="";var oi_param="";var cad_param="";if (url) u="&url="+e(url.replace(/#.*/,"")).replace(/\+/g,"%2B");if (oi) oi_param="&oi="+e(oi);if (cad) cad_param="&cad="+e(cad);new Image().src="/url?sa=T"+oi_param+cad_param+"&ct="+e(ct)+"&cd="+e(cd)+u+"&ei=E8swRYIOkpKwAvzZ8JkB"+sg;}return true;}
            // -->
            </script>
            </head><body bgcolor=#ffffff text=#000000 link=#0000cc vlink=#551a8b alink=#ff0000 onLoad=sf() topmargin=3 marginheight=3><center><div align=right nowrap style="padding-bottom:4px" width=100%><font size=-1><b>manioster@gmail.com</b>&nbsp;|&nbsp;<a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.com/ig%3Fhl%3Dzh-CN&sig=__1eXNMn0jGllmJ57x74DzjVvy6Vk=" onmousedown="return clk('/url?sa=p&pref=ig&pval=3&q=http://www.google.com/ig%3Fhl%3Dzh-CN&sig=__1eXNMn0jGllmJ57x74DzjVvy6Vk=','promos','hppphou:zh-cn_all','pro','1','&sig2=zclmOmtQiZPPuTCMWUJMZA')">個(gè)性化主頁</a>&nbsp;|&nbsp;<a href="https://www.google.com/accounts/ManageAccount">我的帳戶</a>&nbsp;|&nbsp;<a href="http://www.google.com/accounts/Logout?continue=http://www.google.com/intl/zh-CN/">退出</a></font></div><img src="/intl/zh-CN_ALL/images/logo.gif" width=286 height=110 alt="Google"><br><br>
            <form action=/search name=f><script><!--
            function qs(el) {if (window.RegExp && window.encodeURIComponent) {var ue=el.href;var qe=encodeURIComponent(document.f.q.value);if(ue.indexOf("q=")!=-1){el.href=ue.replace(new RegExp("q=[^&$]*"),"q="+qe);}else{el.href=ue+"&q="+qe;}}return 1;}
            // -->
            ..........

            第一個(gè)空行上面的就是“說明”了,下面是html代碼。有了說明,瀏覽器就知道這是什么了,拿到這段數(shù)據(jù)后,就把這些html標(biāo)簽解釋成各種各樣的元素,在瀏覽器上有序地顯示出來。瀏覽器還蠻聰明的,當(dāng)看到<img src=..>標(biāo)簽,那就會(huì)又自己發(fā)一個(gè)請(qǐng)求報(bào)文給服務(wù)器,要求得到一個(gè)圖像文件,請(qǐng)求報(bào)文就像:

            GET /image/pp.jpg HTTP/1.1
            ....

            這樣,服務(wù)器端就找到這個(gè).jpg圖像,加上"說明"之后發(fā)給瀏覽器,瀏覽器收到后就顯示在對(duì)應(yīng)的位置上。遇到包含css、js...的標(biāo)簽也一樣。

            如此重復(fù),一個(gè)完整的web就會(huì)呈現(xiàn)在我們眼前了。

            服務(wù)器端代碼:

            /*****************************************************************

              mymultiwebserver.c 

              system:redhat linux Fedora Core 5

              enviroment:g++

              compile command:g++ -g -o mymultiwebserver -lpthread

              date:10/15/2006

              By Manio

             ****************************************************************
            */

            #include 
            <stdlib.h>

            #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>



            #define PORT 8848

            #define BACKLOG 5

            #define MAXDATASIZE 1000

            #define DEBUG 1

            void process_cli(int connectfd, sockaddr_in client);

            int sendobj(int connectfd,char* serverfilepath);

            int IsDIR(char* fpath);

            int fileordirExist(char* fpath);

            char* getextname(char*);

            int writehead(FILE* cfp, char* extname);

            void* start_routine(void* arg);

            void msg404(int connectfd);



            struct ARG {

                   
            int connfd;

                   sockaddr_in client;

                   };

                   

            main()

            {

                  
            int listenfd, connectfd;

                  pthread_t thread;         
            //id of thread

                  ARG 
            *arg;            //pass this var to the thread

                  
            struct sockaddr_in server; //server's address info

                  
            struct sockaddr_in client; //client's

                  
            int sin_size;

                  

                  
            //create tcp socket

            #ifdef DEBUG

                  printf(
            "socket.... ");

            #endif

                  
            if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

                                perror(
            "creating socket failed.");

                                exit(
            1);

                  }

                  

                  
            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.... ");

                  
            if(bind(listenfd,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {

                      perror(
            "bind error.");

                      exit(
            1);

                  }

                  

                  printf(
            "listen.... ");

                  
            if(listen(listenfd,BACKLOG) == -1) {

                      perror(
            "listen() error ");

                      exit(
            1);

                  }



                  sin_size 
            = sizeof(struct sockaddr_in);

                  
            while(1)

                  {

                      
            //accept() using main thread

                      printf(
            "accepting.... ");

                      
            if((connectfd = accept(listenfd,

                                 (
            struct sockaddr *)&client,

                                 (socklen_t
            *)&sin_size)) == -1) {

                          printf(
            "accept() error ");

                      }



                      arg 
            = new ARG;

                      arg
            ->connfd = connectfd;

                      memcpy((
            void *)&arg->client, &client, sizeof(client));

                    

                      
            //invoke start_routine to handle this thread

            #ifdef DEBUG

                      printf(
            "thread_creating....");

            #endif

                      
            if(pthread_create(&thread, NULL, start_routine, (void*)arg)){

                          perror(
            "pthread_create() error");

                          exit(
            1);

                      }          

                  }

                  close(listenfd);      

            }





            //handle the request of the client

            void process_cli(int connectfd, sockaddr_in client)

            {

                
            int num;

                
            //char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];

                
            char requestline[MAXDATASIZE], filepath[MAXDATASIZE], cmd[MAXDATASIZE],extname[MAXDATASIZE];

                
            int c;

                FILE 
            *fp;

                FILE 
            *cfp;

                fp 
            = fdopen(connectfd,"r");    

                

            #ifdef DEBUG

                printf(
            "the host is:%s  ",inet_ntoa(client.sin_addr) );

            #endif

                fgets(requestline,MAXDATASIZE,fp);

            #ifdef DEBUG

                printf(
            " THE REQUEST IS :%s ",requestline);

            #endif

                strcpy(filepath,
            "./");

                sscanf(requestline,
            "%s%s",cmd,filepath+2);

                strcpy(extname, getextname(filepath));

            #ifdef DEBUG

                printf(
            "cmd:%s filepath:%s extname:%s ",cmd,filepath,extname);

                

                printf(
            "string comparing :::::::::::::start::::::::::::::: ");    

            #endif

                
            if(strcmp(cmd,"GET"== 0){

                
            //the command is get

            #ifdef DEBUG

                    printf(
            "cmd(%s)==GET ",cmd);

            #endif

                    
            //is this a file or dir or notexist?

                    
            if(fileordirExist(filepath)){

                    
            //is a file or dir or none

                        
            //is this a dir 

                        
            if(IsDIR(filepath)){

                            
            //is a dir

            #ifdef DEBUG

                            printf(
            "%s is a DIR ",filepath);

            #endif

                            
            if( fileordirExist( strcat(filepath,"index.htm") )){

                                sendobj(connectfd,
            "index.htm");

                            }
            else if(fileordirExist(strcat(filepath,"index.html"))){

                                sendobj(connectfd,
            "index.htm");

                            }
            else{

                                msg404(connectfd);

                            }

                        }
            else{

                                
            //is a file

            #ifdef DEBUG

                                printf(
            "%s is a file",filepath);

            #endif

                                sendobj(connectfd,filepath);

                        }

                    }
            else{

            #ifdef DEBUG

                        printf(
            "404 ");

            #endif

                        msg404(connectfd);

                    }

                }
            else{

            #ifdef DEBUG

                    printf(
            "cmd(%s)!=GET ",cmd);

            #endif

                }

            #ifdef DEBUG

                printf(
            ":::::::::::::end::::::::::::::: ");    

            #endif

                close(connectfd);

            }

            //send the 404 error message to the client

            void msg404(int connectfd)

            {

                
            char* msg;

                msg  
            = "HTTP/1.0 404 Not Found Content-Type: text/plain 404 not found by Manio";

                send(connectfd,msg,strlen(msg),
            0);

            }

            //is the filepath a file  or directory

            int fileordirExist(char* fpath)

            {

                
            struct stat filestat;

                
            return (  stat(fpath,&filestat) != -1);

            }



            // is the filepath a directory

            int IsDIR(char* fpath)

            {

            #ifdef DEBUG

                printf(
            "IN IsDIR ");

            #endif

                
            struct stat filestat;

                
            return ( stat(fpath,&filestat) != -1 && S_ISDIR(filestat.st_mode));

            }



            //send the data of the file which the client want

            int sendobj(int connectfd,char* serverfilepath)

            {

                FILE
            * sfp,*cfp;

                
            int c;

                sfp 
            = fopen(serverfilepath,"r");

                cfp 
            = fdopen(connectfd,"w");



                writehead(cfp,getextname(serverfilepath));

                
            while( (c = getc(sfp)) != EOF)putc(c,cfp);    

                fflush(cfp);

                
            return 0;

            }

            //write the packet header to the client

            int writehead(FILE* cfp, char* extname)

            {

            #ifdef DEBUG

                printf(
            "INWRITEHEAD:::::::extname is %s::::::: ",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 
            = "image/gif";

                
            else if ( strcmp(extname,"jpeg"== 0 || strcmp(extname,"jpg"== 0)

                    content 
            = "image/jpeg";

                
            else if ( strcmp(extname,"png"== 0)

                    content 
            = "image/png";

            #ifdef DEBUG

                printf(
            "HTTP/1.1 200 OK ");

                printf(
            "Content-Type: %s ",content);

            #endif

                fprintf(cfp,
            "HTTP/1.1 200 OK ");

                fprintf(cfp,
            "Content-Type: %s ",content);

                
            return 0;

            }



            //get the extent name of the file

            char* getextname(char* filepath)

            {

                
            char* p;

                
            if(( p  =  strrchr(filepath,'.')) != NULL)

                           
            return p+1;

                
            return NULL;           

            }



            //invoked by pthread_create

            void* start_routine(void* arg)

            {

                ARG 
            *info;

                info 
            = (ARG *)arg;

                
            //handle client's requirement

                process_cli(info
            ->connfd, info->client);



                delete arg;

                pthread_exit(NULL);

            }

             

            運(yùn)行方法:

            在fc5中打開控制臺(tái),按下面的方法進(jìn)行

            [root@localhost webserver1707]# ls
            admin           header   img        index.htm~
            chinaunix.html  header~  index.htm  mymultiwebserver.c
            [root@localhost webserver1707]# g++ -g -o mymultiwebserver mymultiwebserver.c -lpthread
            mymultiwebserver.c: In function 鈥榲oid* start_routine(void*)鈥?
            mymultiwebserver.c:253: 璀﹀憡錛氬垹闄?鈥榲oid*鈥?鏈畾涔?[root@localhost webserver1707]# ./mymultiwebserver socket....
            bind....
            listen....
            accepting....
            thread_creating....accepting....
            the host is:127.0.0.1
            THE REQUEST IS :GET / HTTP/1.1

            cmd:GET
            filepath:.//
            extname://
            string comparing
            :::::::::::::start:::::::::::::::
            cmd(GET)==GET
            IN IsDIR
            .// is a DIR
            INWRITEHEAD:::::::extname is htm:::::::
            HTTP/1.1 200 OK
            Content-Type: text/html

            thread_creating....accepting....
            :::::::::::::end:::::::::::::::
            thread_creating....accepting....
            the host is:127.0.0.1
            THE REQUEST IS :GET /img/sb.jpg HTTP/1.1

            cmd:GET
            filepath:.//img/sb.jpg
            extname:jpg
            string comparing
            :::::::::::::start:::::::::::::::
            cmd(GET)==GET
            IN IsDIR
            .//img/sb.jpg is a fileINWRITEHEAD:::::::extname is jpg:::::::
            HTTP/1.1 200 OK
            Content-Type: image/jpeg

            :::::::::::::end:::::::::::::::
            the host is:127.0.0.1
            THE REQUEST IS :GET /img/gcc.png HTTP/1.1

            cmd:GET
            filepath:.//img/gcc.png
            extname:png
            string comparing
            :::::::::::::start:::::::::::::::
            cmd(GET)==GET
            IN IsDIR
            .//img/gcc.png is a fileINWRITEHEAD:::::::extname is png:::::::
            HTTP/1.1 200 OK
            Content-Type: image/png

            :::::::::::::end:::::::::::::::

            放一個(gè)index.htm文件在此程序所在的文件夾,打開瀏覽器,在地址欄輸入http://127.0.0.1:8848/,就可以看到網(wǎng)頁了~

            posted on 2008-07-02 09:49 隨意門 閱讀(4801) 評(píng)論(1)  編輯 收藏 引用

            評(píng)論

            # re: 一個(gè)多線程web服務(wù)器實(shí)例(C,Linux,詳細(xì)的web服務(wù)器原理) 2013-10-01 21:13 OverSeven

            只能訪問一次,第二次訪問就出錯(cuò).

            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            AV无码久久久久不卡蜜桃| 色综合久久综合网观看| 久久精品www人人爽人人| 久久超碰97人人做人人爱| 久久久青草青青国产亚洲免观| 久久久久精品国产亚洲AV无码| AV色综合久久天堂AV色综合在| 久久99精品九九九久久婷婷| 无码超乳爆乳中文字幕久久 | 精品视频久久久久| 一本久道久久综合狠狠躁AV| 国产精品久久网| 久久久久久久久波多野高潮| 亚洲国产精品久久久久婷婷软件 | 精品久久久久久久无码| 日批日出水久久亚洲精品tv| 7777久久亚洲中文字幕| 精品久久久久成人码免费动漫| 精品综合久久久久久97超人 | 漂亮人妻被黑人久久精品| 久久99精品久久久久久齐齐| 久久夜色精品国产欧美乱| 久久亚洲AV无码西西人体| 国产精品内射久久久久欢欢| 久久人人爽爽爽人久久久| 欧美日韩精品久久久免费观看| 国产精品成人久久久久三级午夜电影| 婷婷伊人久久大香线蕉AV | 国内高清久久久久久| 一极黄色视频久久网站| 狠狠色丁香婷婷综合久久来来去| av无码久久久久久不卡网站| 日韩AV无码久久一区二区 | 久久精品国产欧美日韩| 中文字幕一区二区三区久久网站| 亚洲AV无码久久精品成人| 精品国产乱码久久久久久呢 | 青草影院天堂男人久久| 国产精品久久久久久搜索| 97久久超碰国产精品旧版| 91精品国产91久久久久久蜜臀|