webserver通信过程

10 篇文章 0 订阅

 

 

 简单的http服务器


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
 
#define N 1024
#define ERR_LOG(errmsg) do{\
                            perror(errmsg);\
                            printf("%s - %s - %d\n", __FILE__, __func__, __LINE__);\
                            exit(1);\
                        }while(0)
 
void *pthread_fun(void *arg)
{
    int acceptfd = *(int *)arg;
    char buf[N] = "";
    char head[]="HTTP/1.1 200 OK\r\n"                   \
            "Content-Type: text/html\r\n"       \
            "\r\n";    
    char err[]= "HTTP/1.1 404 Not Found\r\n"        \
        "Content-Type: text/html\r\n"       \
        "\r\n"                              \
        "<HTML><BODY>File not found</BODY></HTML>";
 
    //接收浏览器通过http协议发送的数据包
    if(recv(acceptfd, buf, N, 0) < 0)
    {
        ERR_LOG("fail to recv");
    }
 
    printf("*****************************\n\n");
    printf("%s\n", buf);
    // int i;
    // for(i = 0; i < 200; i++)
    // {
    //     printf("[%c] - %d\n", buf[i], buf[i]);
    // }
    printf("\n*****************************\n");
 
    //通过获取的数据包中得到浏览器要访问的网页文件名
    //GET /about.html http/1.1
    char filename[128] = "";
    sscanf(buf, "GET /%s", filename);   //sscanf函数与空格结束,所以直接可以获取文件名
     
    if(strncmp(filename, "HTTP/1.1", strlen("http/1.1")) == 0)
    {
        strcpy(filename, "about.html");
    }
    printf("filename = %s\n", filename);
 
    char path[128] = "./sqlite/";
    strcat(path, filename);
 
    //通过解析出来的网页文件名,查找本地中有没有这个文件
    int fd;
    if((fd = open(path, O_RDONLY)) < 0)
    {
        //如果文件不存在,则发送不存在对应的指令
        if(errno == ENOENT)
        {
            if(send(acceptfd, err, strlen(err), 0) < 0)
            {
                ERR_LOG("fail to send");
            }
 
            close(acceptfd);
            pthread_exit(NULL);
        }
        else
        {
            ERR_LOG("fail to open");
        }
    }
 
    //如果文件存在,先发送指令告知浏览器
    if(send(acceptfd, head, strlen(head), 0) < 0)
    {
        ERR_LOG("fail to send");
    }
 
    //读取网页文件中的内容并发送给浏览器
    ssize_t bytes;
    char text[1024] = "";
    while((bytes = read(fd, text, 1024)) > 0)
    {
        if(send(acceptfd, text, bytes, 0) < 0)
        {
            ERR_LOG("fail to send");
        }
    }
 
    pthread_exit(NULL);
}
 
int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr, "Usage: %s <server_ip> <server_port>\n", argv[0]);
        exit(1);
    }   
 
    int sockfd, acceptfd;
    struct sockaddr_in serveraddr, clientaddr;
    socklen_t addrlen = sizeof(serveraddr);
 
    //第一步:创建套接字
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        ERR_LOG("fail to socket");
    }
 
    //将套接字设置为允许重复使用本机地址或者为设置为端口复用
    int on = 1;
    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
    {
        ERR_LOG("fail to setsockopt");
    }
 
    //第二步:填充服务器网络信息结构体
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));
 
    //第三步:将套接字与服务器网络信息结构体绑定
    if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0)
    {
        ERR_LOG("fail to bind");
    }
 
    //第四步:将套接字设置为被动监听状态
    if(listen(sockfd, 5) < 0)
    {
        ERR_LOG("fail to listen");
    }
 
    while(1)
    {
        //第五步:阻塞等待客户端的连接请求
        if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
        {
            ERR_LOG("fail to accept");
        }
 
        //打印客户端的信息
        printf("%s -- %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
 
        //创建线程接收数据并处理数据
        pthread_t thread;
        if(pthread_create(&thread, NULL, pthread_fun, &acceptfd) != 0)
        {
            ERR_LOG("fail to pthread_create");
        }
        pthread_detach(thread);
 
    }
 
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值