zoukankan      html  css  js  c++  java
  • 简单的listen+fork accept服务器实现

    前段时间在分析nginx的IO模型的时候,知道nginx采用的是一进程监听+多进程accept的模式,也就是主进程先创建socket并bind指定端口listen之后,再fork出若干个子进程,由子进程去accept连接请求。

    这段时间将其用代码实现并验证了一遍,监听端口后对接受到的请求,按照http协议返回进程id,算是一个极其简单的web服务器吧,后续对http协议的内容了解深入之后,看看再怎么对其扩展下。

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    
    int s;//socket
    typedef enum//定义bool类型,c语言中没有bool类型
    {
        false,
        true
    }bool;
    
    bool init (const char* addr, const short port)
    {
        struct sockaddr_in servaddr;
        
        s = socket(AF_INET, SOCK_STREAM, 0); 
        if(-1 == s)
            return false;
        memset(&servaddr, 0, sizeof(servaddr));  
        servaddr.sin_family = AF_INET;
        if(inet_pton(AF_INET, addr, &servaddr.sin_addr) < 0)
            return false;
        servaddr.sin_port = htons(port);
        if(bind(s, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) 
        {   
            printf("port is in use
    ");
            return false;
        }   
        if(listen(s, 10) == -1) 
            return false;
        
        printf("init success! listen port %d
    ", port);
        return true;
    }
    
    void do_cycle()
    {
        int connect_fd;
        char rcvbuf[102400];
        char sndbuf[102400];
        pid_t pid = getpid();
    
        while(true)
        {
            if((connect_fd = accept(s, (struct sockaddr*)NULL, NULL)) == -1)
            {
                printf("accept socket error
    ");
                continue;
            }
    
            recv(connect_fd, rcvbuf, 102400, 0);
            snprintf(sndbuf, 102400, "HTTP/1.1 200 OK
    
    <html><head><title>hello</title></head><body>process id: %d</body></html>", pid);
            send(connect_fd, sndbuf, strlen(sndbuf), 0);
            close(connect_fd);
        }
    }
    
    void loop_cycle(int process_num)
    {
        int i, j;
        pid_t pid;
        pid_t sub_ids[process_num];
        char killstr[1024];
        char ch;
        if(1 == process_num)
            do_cycle();
        else
        for (i = 0; i < process_num; i++)
        {
            pid = fork();
            if(pid < 0)
            {
                printf("fork error
    ");
                for(j = 0; j < i; j++)
                {
                    snprintf(killstr, 1024, "kill -9 %d", sub_ids[j]);
                    system(killstr);
                }
    
                return;
            }
            if(pid == 0)
                do_cycle();
            if(pid > 0)
                sub_ids[i] = pid;
        }
        while(true)
        {
            scanf("%c", &ch);
            if(ch == 'q')
            {
                for(j = 0; j < process_num; j++)
                {
                    snprintf(killstr, 1024, "kill -9 %d", sub_ids[j]);
                    system(killstr);
                }
                close(s);
                break;
            }
        }
    }
    
    
    int main(int argc, char* args[])
    {
        int port, pro_num;
        if(argc < 4)
        {
            printf("usage: hs <ip> <port> <process num>
    ");
            return 0;
        }
        port = atoi(args[2]);
        pro_num = atoi(args[3]);
        if(!init(args[1], port))
            return 0;
    
        loop_cycle(pro_num);
        return 0;
    }

    在init函数中,创建socket并进行监听,然后在loop_cycle中fork子进程,由子进程进行循环接收处理数据,父进程等待用户输入,如果用户输入退出指令,结束所有子进程并退出。
    运行程序:


    启动后,用浏览器访问效果:

    返回了进程id.

    
    
  • 相关阅读:
    EMES信息化制造系统的概念
    正则表达式校验日期、时间
    c#怎么string转化成ascii码
    C#实现将一个字符串进行翻转显示的6种方法,数组的 Reverse()反转方法
    把一个十六进制的字符串(包含0x或0X)转化成对应的数值 ASCII码
    为什么0-9转化成字符是+0x30,11转化成A是+0x37?
    oracle修改数据库字段长度
    表添加字段的SQL语句写法
    在数据表中添加一个字段的SQL语句怎么写-百度
    oracle创建表增加字段sql脚本,字段说明注释
  • 原文地址:https://www.cnblogs.com/yutongqing/p/6687454.html
Copyright © 2011-2022 走看看