用 C 語言編寫多程式 Web 伺服器【粗暴版】

勺顛顛發表於2019-08-30

php編寫多程式web伺服器
同樣是使用select來實現,以上是php版本的原始碼,select IO模型複用主要是輪詢方式監聽檔案描述符集,它依然是阻塞方式
具體可以參閱我做的說明。在此不再細說。網路卡是怎麼接收到資料,怎麼把資料寫入對應的sock的,到底怎麼搞的,自己去看看。
在您閱讀時:勿必瞭解下程式,程式組,程式排程,守護程式,前臺程式,IO模型,網路卡讀寫原理,中斷系統,主機位元組序和網路位元組序列,tcp狀態轉移圖,tcp抓包,socket地址型別,一些相關的資料結構如線性表的連結串列儲存,二叉樹插入和刪除,以及平衡二叉樹【紅黑樹】相關概念【以便你深入理解IO模型select和epoll的區別相關知識】

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libgen.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
int pids[10];
int main(int argc,char *argv[])
{
        if(argc<2){
                printf("useage:%s ip and port\n",basename(argv[0]));
                exit(0);
        }

        char const *ip = argv[1];
        int port = atoi(argv[2]);

        struct sockaddr_in address;
        bzero(&address,sizeof(address));

        address.sin_family = AF_INET;
        address.sin_port = htons(port);
        inet_pton(AF_INET,ip,&address.sin_addr);

        int sockfd = socket(PF_INET,SOCK_STREAM,0);//建立sock檔案描述符,預設從最小的值開始,最小的值是多少,可以自己去想想程式啟動時預設開啟幾個檔案描述符,程式退出時又關閉了幾個,想想程式啟動前幹什麼了,在此不再多說,建立的sock會關聯自己的接受和傳送緩衝區
        assert(sockfd>0);

        int ret = bind(sockfd,(struct sockaddr*)&address,sizeof(address));//繫結ip和埠號
        assert(ret!=-1);

        ret = listen(sockfd,1024);//啟用監聽  並且處於LISTEN狀態【tcp狀態轉移圖自己去看本人前面說過的資料】
    //檔案描述集合初始化【或許你在linux玩上一陣子才好理解^_^】
        fd_set readfds;
        fd_set writefds;
        fd_set exceptionfds;
        fd_set reads;
        fd_set writes;
        fd_set exceptions;
        FD_ZERO(&readfds);
        FD_ZERO(&writefds);
        FD_ZERO(&exceptionfds);
        FD_ZERO(&reads);
        FD_ZERO(&writes);
        FD_ZERO(&exceptions);
        int i;

        int listenfd = sockfd;

        FD_SET(sockfd,&readfds);
        FD_SET(sockfd,&writefds);
        FD_SET(sockfd,&exceptionfds);

        struct timeval tv;
        tv.tv_sec=0;
        tv.tv_usec=0;

        pid_t pid = fork();
        if(pid<0|pid>0){
                exit(0);
        }

        if(setsid()<0){
                exit(0);
        }

        for(i=0;i<4;i++){

                pid_t pid = fork();

                if(pid<0){
                        exit(0);
                }
                else if(pid>0){
                        pids[i] = pid;
                }else if(pid==0){

                        //FD_SET(sockfd,&readfds);
                        //FD_SET(sockfd,&writefds);
                        //FD_SET(sockfd,&exceptionfds);
                        int j;
                        srand((unsigned int)time(NULL));
                        while(1){
                                //FD_ZERO(&readfds);
                                //FD_ZERO(&writefds);
                                //FD_ZERO(&exceptionfds);

                                //FD_SET(sockfd,&readfds);
                                //FD_SET(sockfd,&writefds);
                                //FD_SET(sockfd,&exceptionfds);

                                reads = readfds;
                                writes = writefds;
                                exceptions = exceptionfds;
                        //      printf("%d child process select\n",getpid());
                        //不用等,輪詢【檔案集合】時直接返回,tv為null時會阻塞【tv=0時直接返回】
                                int ret = select(listenfd+1,&reads,&writes,&exceptions,&tv);
                        //      printf("ret=%d\n",ret);
                                if(ret<0){

                                        printf("某程式%d退出\n",getpid());
                                        exit(0);
                                }
                                if(ret==0){
                                        continue;
                                }

                                for(j=0;j<listenfd+1;j++){
                                        if(FD_ISSET(j,&reads)){
                                                if(j == sockfd){
                                                        struct sockaddr_in client;
                                                        socklen_t client_len = sizeof(client);
                                                        int connfd = accept(sockfd,(struct sockaddr*)&client,&client_len);
                                                //      if(connfd>0){
                                                                printf("%d child 當前的客戶端檔案描述符是:%d\n",getpid(),connfd);

                                                                FD_SET(connfd,&readfds);
                                                                FD_SET(connfd,&writefds);
                                                                FD_SET(connfd,&exceptionfds);

                                                                if(listenfd<connfd)listenfd = connfd;
                                                                printf("listenfd=%d\n",listenfd);
                                                //      }

                                                //      write(connfd,"hi",3);
                                                }else{
                                                        char data[1024];
                                                        int len = read(j,data,sizeof(data));
                                                        if(len==0){
                                                                FD_CLR(j,&readfds);
                                                                FD_CLR(j,&writefds);
                                                                FD_CLR(j,&exceptionfds);
                                                                printf("555");
                                                        }
                                                        //FD_SET(j,&writefds);
                                                        printf("接受內容是:%s of %d\n",data,len);
                                                }
                                        }
                                        if(FD_ISSET(j,&writes)){

                                                char *data = "hello,world";

                                                int len = write(j,data,strlen(data));
                                                printf("某程式[%d]傳送了%d的%s\n",getpid(),len,data);
                                                FD_CLR(j,&readfds);
                                                FD_CLR(j,&writefds);
                                                FD_CLR(j,&exceptionfds);
                                                close(j);
                                        }
                                        if(FD_ISSET(j,&exceptions)){
                                                printf("出錯了\n");
                                                FD_CLR(j,&readfds);
                                                FD_CLR(j,&writefds);
                                                FD_CLR(j,&exceptionfds);
                                        }
                                }
                        }
                }
        }
        close(sockfd);
        return EXIT_SUCCESS;
}

用C語言編寫多程式web伺服器

jackChen

相關文章