【Tinyhttpd学习】C 语言实现最简单的 HTTP 服务器

整体工作流程

Tinyhttpd整体工作流程
(1)服务器启动,在指定端口或者随机端口绑定httpd服务
(2)在收到客户端请求后 ,服务器(主线程)accept这个连接,然后创建一个子线程,执行accept_request函数对这个请求进行处理。
(3)通过accept_request函数 提取出 请求的 方法,url 从而判断客户端的请求 ,如果客户端请求的是静态页面,执行 serve_file函数,直接将请求的数据发送给客户端。如果客户端请求的是cgi文件,执行execute_cgi函数,调用cgi文件,服务器将cgi执行得到的结果发送给客户端。

int main(void)
{
   
int server_sock = -1;
u_short port = 0; //监听端口号
int client_sock = -1;
struct sockaddr_in client_name;
socklen_t client_name_len = sizeof(client_name);
pthread_t newthread;
server_sock = startup(&port);//服务器端监听套接字设置  
printf("httpd running on port %d\n", port);
while(1)
{
   
client_sock = accept(server_sock,
                       (struct sockaddr *)&client_name,
                       &client_name_len);
if (client_sock == -1)//accept失败
   error_die("accept");
if (pthread_create(&newthread , NULL, accept_request,(void *)&client_sock) != 0)
   perror("pthread_create");
}
return(0);
}

各功能模块详述

startup

初始化httpd服务, 建立套接字、绑定端口、进行监听
socket()----bind()—listen()

int startup(u_short * port )
 {
   
    int httpd=0;
 struct sockaddr_in name; // 套接字地址 (地址族/端口地址/ip地址)

 /*int socket(int domain,int type,int protocol)*/
 httpd=socket(PF_INET,SOCK_STREAM,0);
 if(http=-1) //初始化套接口失败 
     error_die("socket");
 /*清空套接字地址*/
 memset(&name,0,sizeof(name));
 name.sin_family=AF_INET;//ipv4
    name.sin_port= htons(*port);//大小端字节表示转换
    name.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY表示本机ip
     if(bind(httpd,(struct sockaddr *)&name, sizeof(name))<0)// 绑定失败
     error_die("bind");
  if(*port == 0) /*动态分配一个端口*/
  {
   
  int namelen = sizeof(name);
  /*在以端口0调用bind 后 ,getsockname 用于返回由内核赋予(动态)的本地端口号*/
  if(getsockname(httpd,(struct sockaddr*)&name,&namelen)==-1) //失败
  error_die("getsockname");
  *port= ntohs(name.sinport);// 网络字节顺序(大端)转换为主机字节顺序
  }
  if(listen(httpd,5)<0) //服务器监听客户端请求。连接队列的最大连接个数设为5
  error_die("listen");
  return(httpd);

涉及一些网络编程的函数
1.socket()
初始化接口,返回socket描述符

int socket(int domain,int type,int protocol);
/*
domain用于设置网络通信的域 PF_INET (Ipv4) 
type 接口类型
SOCK_STREAM TCP套接口
SOCK_DGRAM UDP套接口
protocol 用于制定某个协议的特定类型
通常设为0
*/
  1. bind()
    绑定套接口,成功返回0失败返回-1
int bind(int sockfd,const struct sockaddr * addr,
socklen_t addrlen);
/*
sockfd: socket()返回的socket描述符
addr:该套接字的地址  
struct sockaddr {
   sa_family_t sa_family;
   char        sa_data[14];
}
IP地址和端口一起储存

struct sockaddr_in
      {
        sa_family_t   sin_family; //地址族
 
        uinit16_t sin_port; //16位端口地址
        struct in_addr sin_addr;//32位IP地址
        char zero[8];//不使用 //与 struct sockaddr一样大
       }
      struct in_addr
       {
      in_addr_t s_addr;
       }
 而在 struct sockaddr_in 结构体中 ip地址和端口号是分开储存。
通常 使用struct sockaddr_in设置后,让后将其强制转换为struct sockaddr类型,然后传递给bind函数即可。
addrlen:所指定的结构体变量的大小
*/

3.listen()
使主动连接套接口变为被连接套接口,listen函数只是将 sockfd 和 backlog 告诉内核, 然后就返回。
成功返回0,失败返回1。

int listen(int sockfd,int backlog);
/*
sockfd&
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值