用C一步步開發(fā)web服務器(2)

順著教程1往下走,這個章節(jié)我們需要開發(fā)支持并發(fā)的web服務器,并加入容錯處理

首先加入容錯處理,建議將socket函數(shù)封裝在新的wrap_socket.c文件中结执,并創(chuàng)建他的.h文件,Server端include該文件艾凯,重寫Server端的部分代碼。

wrap_socket.c文件應該是這樣的:

#include "wrap_socket.h"

#define MAXLINE 1000

void p_error(char *str) {
    printf("%s\n",str);
}
/*==========================*/
/* 這里是所有socket方法的封裝*/
/*==========================*/
int Socket(int family,int type,int protocol) {
    int socketfd = socket(family, type, protocol);
    
    if(socketfd < 0) {
        p_error("socket connect error\n");
        return -1;
    }
    return socketfd;
}

void Bind(int fd, const struct sockaddr *sa, socklen_t len) {
    if(bind(fd, sa, len) < 0 )
        p_error("bind connect error\n");
}
void Listen(int fd,int backlog_size) {
    if(listen(fd, backlog_size) < 0)
        p_error("listen client error\n");
}
int Accept(int fd,const struct sockaddr *sa,socklen_t *len) {
    int clientfd = accept(fd, sa, len);
    if(clientfd < 0)
        p_error("can't accept clientserver\n");
    return clientfd;
}
void Connect(int fd,const struct sockaddr *sa,socklen_t len) {
    if(connect(fd, sa, len) < 0)
       p_error("connect to webserver error\n");
}
long Read(int fd, void *buf, size_t len) {
    long n;
    if((n = read(fd, buf, len)) == -1)
        p_error("read error\n");
    return n;
}
void Write(int fd, void *buf, size_t len) {
    if(write(fd, buf, len) == -1 )
        p_error("write error\n");
}
void Close(int fd) {
    if(close(fd) == -1)
        p_error("close fd error\n");
}

當然他對應的wrap_socket.h應該是這樣的:

#ifndef wrap_socket_h
#define wrap_socket_h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//read方法需要的頭文件
#include <unistd.h>
//socket方法需要的頭文件
#include <sys/socket.h>
#include <sys/types.h>
//htonl 方法需要的頭文件
#include <netinet/in.h>
//inet_ntop方法需要的頭文件
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>


int Socket(int family,int type,int protocol);
int num_sum(int a,int b);
void Bind(int fd, const struct sockaddr *sa, socklen_t len);
void Listen(int fd,int backlog_size);
int Accept(int fd,const struct sockaddr *sa,socklen_t *len);
void Connect(int fd,const struct sockaddr *sa,socklen_t len);
long Read(int fd, void *buf, size_t len);
void Write(int fd, void *buf, size_t len);
void Close(int fd);

#endif /* wrap_socket_h */

這個時候 需要重寫下webserver.c的部分socket文件了

 listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    //初始化myaddr參數(shù)
    bzero(&servaddr, sizeof(servaddr)); //結構體清零
    //對servaddr 結構體進行賦值
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);
    
    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    
    Listen(listenfd, BACKLOGSIZE);

這個時候懂傀,跑下程序吧趾诗。調下bug,看看能不能順利運行

接下來我們可以這樣嘗試蹬蚁,在開啟一個Client 與Server交互的時候恃泪,<b>再開啟另一個Client連接Server</b>,看能不能順利運行犀斋,為什么贝乎?

這時候程序要能夠支持并發(fā)的能力,就需要fork()這個方式叽粹,找個簡單的例子說明下fork是這樣的運行方式的

#include <unistd.h>  
#include <stdio.h>   
int main ()   
{   
    pid_t fpid; //fpid表示fork函數(shù)返回的值  
    int count=0;  
    fpid=fork();   
    if (fpid < 0)   
        printf("error in fork!");   
    else if (fpid == 0) {  
        printf("i am the child process, my process id is %d/n",getpid());   
        printf("我是爹的兒子/n");//對某些人來說中文看著更直白览效。  
        count++;  
    }  
    else {  
        printf("i am the parent process, my process id is %d/n",getpid());   
        printf("我是孩子他爹/n");  
        count++;  
    }  
    printf("統(tǒng)計結果是: %d/n",count);  
    return 0;  
} 

當然我們這個程序也是要加上這個fork進行并發(fā)處理的,話不多說虫几,獻上代碼

    //死循環(huán)中進行accept()
    while (1) {
        cliaddr_len = sizeof(cliaddr);
        
        //accept()函數(shù)返回一個connfd描述符
        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
        //fork()方法 創(chuàng)建一個跟父進程一摸一樣的進程 pid <0 表示fork失敗 pid==0表示為子進程 pid>0 為父進程 其pid=getpid();
        pid = fork();
        if(pid < 0) {
            printf("fork error\n");exit(1);
        }else if(pid == 0) {
            while (1) {
                n = Read(connfd, buf, MAXLINE);
                if (n == 0) {
                    printf("the other side has been closed.\n");
                    break;
                }
                printf("received from %s at PORT %d,message is %s\n",
                       inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                       ntohs(cliaddr.sin_port),buf);
                for (i = 0; i < n; i++)
                    buf[i] = toupper(buf[i]);
                write(connfd, buf, n);
            }
            Close(connfd);
            exit(0);
        }else {
            Close(connfd);
        }

    }

到此锤灿,大家試一試運行下,再開啟新的client看看能不能順利訪問,我們還可以通過linux命令查看進程情況

ps -ef | grep webserver

初次啟動是這樣的


first_start_server.png

然后運行client辆脸,并多運行幾次但校,就呃可以看到進程數(shù)在增加

second_start_server.png

好了,這個章節(jié)關于錯誤處理以及fork的內容到這了啡氢,第3章就開始真正進行web服務器的開發(fā)了原文章鏈接

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末状囱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子倘是,更是在濱河造成了極大的恐慌亭枷,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辨绊,死亡現(xiàn)場離奇詭異奶栖,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門宣鄙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來袍镀,“玉大人,你說我怎么就攤上這事冻晤∥郏” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵鼻弧,是天一觀的道長设江。 經(jīng)常有香客問我,道長攘轩,這世上最難降的妖魔是什么叉存? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮度帮,結果婚禮上歼捏,老公的妹妹穿的比我還像新娘。我一直安慰自己笨篷,他們只是感情好瞳秽,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著率翅,像睡著了一般练俐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冕臭,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天腺晾,我揣著相機與錄音,去河邊找鬼浴韭。 笑死丘喻,一個胖子當著我的面吹牛,可吹牛的內容都是我干的念颈。 我是一名探鬼主播泉粉,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼榴芳!你這毒婦竟也來了嗡靡?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤窟感,失蹤者是張志新(化名)和其女友劉穎讨彼,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柿祈,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡哈误,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年哩至,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜜自。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡菩貌,死狀恐怖,靈堂內的尸體忽然破棺而出重荠,到底是詐尸還是另有隱情箭阶,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布戈鲁,位于F島的核電站仇参,受9級特大地震影響,放射性物質發(fā)生泄漏婆殿。R本人自食惡果不足惜诈乒,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望婆芦。 院中可真熱鬧抓谴,春花似錦、人聲如沸寞缝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荆陆。三九已至,卻和暖如春集侯,著一層夾襖步出監(jiān)牢的瞬間被啼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工棠枉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留浓体,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓辈讶,卻偏偏與公主長得像命浴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子贱除,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內容