Linux网络编程-简单web服务器

简单web服务器 

//web.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <signal.h>
#include <sys/wait.h>

#include "wrap.h"

#define BUFF_SIZE 1024
#define SERV_PORT 8000

void handle_sig(int sig)
{
    printf("child exit\n");
    wait(NULL);
}

char *http_res_tmpl = "HTTP/1.1 200 OK\r\n"
        "Server: Cleey's Server V1.0\r\n"
        "Accept-Ranges: bytes\r\n"
        "Content-Length: %d\r\n"
        "Connection: close\r\n"
        "Content-Type: %s\r\n\r\n";

void http_send(int sock_client,char *content){
        char HTTP_HEADER[BUFF_SIZE],HTTP_INFO[BUFF_SIZE];
        int len = strlen(content);
        sprintf(HTTP_HEADER,http_res_tmpl,len,"text/html");
        len = sprintf(HTTP_INFO,"%s%s",HTTP_HEADER,content);

        Write(sock_client,HTTP_INFO,len);
}

int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    char buf[BUFF_SIZE];
    char str[INET_ADDRSTRLEN];
    int i, n;

    struct sigaction act;
    act.sa_handler = handle_sig;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGCHLD,&act,NULL);


    listenfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    int opt = 1;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    Listen(listenfd, 20);

    printf("Accepting connections ...\n");
    while(1) {
        cliaddr_len = sizeof(cliaddr);
        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);

        n = fork();
        if ( n == -1) {
            perror("call to fork");
            exit(1);
        } else if (n == 0) { // child
            Close(listenfd);

            n = Read(connfd, buf, BUFF_SIZE);
            if (n == 0) {
                printf("the other side has been closed.\n");
                break;
            }
            printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port));
            fputs(buf, stdout);
            http_send(connfd, "hello world!");
            Close(connfd);
            exit(0);
       } else {  // parent
            Close(connfd);
       }
    }
}
//wrap.h
#ifndef WRAP_H
#define WRAP_H

void perr_exit(const char *s);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
void Bind(int fd, const struct sockaddr *sa, socklen_t salen);
void Connect(int fd, struct sockaddr *sa, socklen_t salen);
void Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, void *ptr, size_t nbytes);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t Readline(int fd, void *vptr, size_t maxlen);
void Close(int fd);

#endif
//wrap.c

#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>

void perr_exit(const char *s)
{
    perror(s);
    exit(1);
}

int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
    int n;
again:
    if ((n = accept(fd, sa, salenptr)) < 0) {
        if ((errno == ECONNABORTED) || (errno == EINTR)) {
            goto again;
        } else {
            perr_exit("accept error");
        }
    }
    return n;
}

void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    if(bind(fd, sa, salen) < 0){
        perr_exit("bind error");
    }
}

void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
    if (connect(fd, sa, salen) < 0) {
        perr_exit("connect error");
    }
}

void Listen(int fd, int backlog)
{
    if(listen(fd, backlog) < 0){
        perr_exit("listen error");
    }
}

int Socket(int family, int type, int protocol)
{
    int n;
    if ((n = socket(family, type, protocol)) < 0) {
        perr_exit("socket error");
    }
    return n;
}

ssize_t Read(int fd, void *ptr, size_t nbytes)
{
    ssize_t n;
again:
    if((n = read(fd, ptr, nbytes)) == -1) {
        if(errno == EINTR) {
            goto again;
        } else {
            return -1;
        }
    }
    return n;
}

ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
    ssize_t n;
again:
    if ((n = write(fd, ptr, nbytes)) == -1) {
        if (errno == EINTR) {
            goto again;
        } else {
            return -1;
        }
    }
    return n;
}

ssize_t Readn(int fd, void *vptr, size_t n)
{
    size_t nleft;
    ssize_t nread;
    char *ptr;

    ptr = vptr;
    nleft = n;
    while(nleft > 0) {
        if( (nread = read(fd, ptr, nleft)) < 0) {
            if( errno == EINTR ) {
                nread = 0;
            }else if( nread == 0 ) {
                break;
            }
        }

        nleft -= nread;
        ptr += nread;
    }
    return n - nleft;
}

ssize_t Writen(int fd, const void *vptr, size_t n)
{
    size_t nleft;
    ssize_t nwrittrn;
    const char *ptr;

    ptr = vptr;
    nleft = n;

    while(nleft > 0) {
        if (( nwrittrn = write(fd, ptr, nleft)) <= 0) {
            if (nwrittrn  < 0 && errno == EINTR) {
                nwrittrn = 0;
            } else {
                return -1;
            }
        }

        nleft -= nwrittrn;
        ptr += nwrittrn;
    }
    return n;
}

static ssize_t my_read(int fd, char *ptr) {
    static int read_cnt;
    static char *read_ptr;
    static char read_buf[100];

    if (read_cnt <= 0) {
    again:
        if((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
            if (errno == EINTR) {
                goto again;
            }
            return -1;
        } else if(read_cnt == 0) {
            return 0;
        }
        read_ptr = read_buf;
    }
    read_cnt --;
    *ptr = *read_ptr++;
    return 1;
}


ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
    ssize_t n, rc;
    char c, *ptr;

    ptr = vptr;
    for (n = 0; n < maxlen; n++) {
        rc = my_read(fd, &c);
        if (rc == 1) {
            *ptr++ = c;
            if (c == '\n') {
                break;
            }
        }else if(rc == 0) {
            *ptr = 0;
            return n-1;
        }else {
            return -1;
        }
    }

    *ptr = 0;
    return n;
}

void Close(int fd)
{
    if(close(fd) == -1) {
        perr_exit("close error");
    }

}

1. 执行 gcc web.c wrap.c -o web

2. 执行 ./web

3. 在浏览器中输入 http://127.0.0.1:8000

4. 浏览器截图如下

zfz:Demo zhangfengzhou$ ./web
Accepting connections ...
received from 127.0.0.1 at PORT 57167
GET / HTTP/1.1
Host: 127.0.0.1:8000
Connection: keep-alive
sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: _ga=GA1.1.1119943947.1618886138

child exit

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Webadmin!是一个免费的开源框架,用于为Linux系统的快速搭建统一、稳定、易用的Web管理系统。 WebAdmin系统由三部分组成:WEB图形用户接口、WebAdmin守护进程和进程监视程序。Web图形用户接口(WebGUI)是WebAdmin系统的前端部分,为用户提供一个统一、易操作的图形界面。WebAdmin守护进程 (WebAdmind)是WebAdmin系统的后台部分,实时监视WebGUI生成的配置文件,并根据配置文件的变化情况,启动或停止相应的服务进程,WebAdmin进程监视程序(DaemonWatcher)用于实时监视WebAdmind启动的服务进程的运行状况,一旦发现启动的服务进程异常中止,立即重启中止的服务进程,从而确保系统可靠稳定运行。 WebAdmin!提供了一个结构化的WebAdmin开发框架,它的前后台部分均采用插件式的程序开发方法,借助提供的插件开发模板,WebAdmin系统开发者不必关WebAdmin开发框架的具体实现,就可设计出界面统一、操作简单、安全稳定的WebGUI界面。与WebGUI相对应,Webadmind也是采用插件式的程序开发方法。WebAdmind插件与WebGUI插件一一对应完成对界面操作的响应。DaemonWatcher是一个独立的进程监视程序,是为确保WebAdmind启动的进程能够不可间断地提供服务,一旦发现被监视程序发生异常中止,DaemonWatcher将根据进程的启动脚本立即启动被中止进程。 WebAdmin是一个用C语言设计的易用的图形用户接口开发框架,C语言的高可移植性使得WebAdmin可以广泛应用于包括Linux、Unix、Windows及各种嵌入式操作系统中,编译WebAdmin系统除Libxml2库处不需要额外的C函数库支持。WebAdmin提供了丰富的API函数,开发者可以根据自己的需要定制个性化的WebAdmin系统。 WebAdmin系统的界面风格也可以自己定制,对于OEM厂商可以根据需要修改界面风格,满足定制要求。 WebAdmin的开放设计思想,为WebAdmin系统的不断发展普奠定了基础,无数开发者提供了开源插件模块,用户甚至不用写一行代码就可根据自己的需要设计WebAdmin系统。 【简单使用方法】:下载后将压缩文件上传到Linux系统中,用tar xvfz webadmin-devel-1.3.tar.gz解压,解压后进入webadmin-devel目录,执行./configure,make命令后将会在test/webui目录下生成一个webadmin.cgi文件,将此文件拷贝到apache下的WEB根目录下cgi-bin目录下即可,为测试webadmin.cgi,还需将htdocs目录下的文件拷贝到apache的WEB根目录下,将etc目录中的所有文件拷贝到根目录下的etc中,最后用浏览器访问你的apache Web服务器即可看到Linux系统的WEB管理界面。 【说明】:编译此源码需要libxml2库的支持 有技术问题可以访问官方网站:http://www.webadminc.com,联系电话:13311223928
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值