b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

TinyHttpd----超轻量型Http Server源码分析(2)

电脑杂谈  发布时间:2019-09-05 12:03:11  来源:网络整理

读取文件中数据发送到client:cat函数

//把文件resource中的数据读取到client中
void cat(int client, FILE *resource)
{
 char buf[1024];
/从文件结构指针resource中读取数据,保存至buf中  
 fgets(buf, sizeof(buf), resource);
 //处理文件流中剩下的字符  
 //检测流上的文件结束符,文件结束返回非0值,结束返回0  
 while (!feof(resource))
 {
  send(client, buf, strlen(buf), 0);
  fgets(buf, sizeof(buf), resource);
 }
}

将信息传送个client:headers, serve_file

/服务器向client发送响应头部信息
void headers(int client, const char *filename)
{
 char buf[1024];
 (void)filename;  /* could use filename to determine file type */
 strcpy(buf, "HTTP/1.0 200 OK\r\n");
 send(client, buf, strlen(buf), 0);
 strcpy(buf, SERVER_STRING);
 send(client, buf, strlen(buf), 0);
 sprintf(buf, "Content-Type: text/html\r\n");
 send(client, buf, strlen(buf), 0);
 strcpy(buf, "\r\n");
 send(client, buf, strlen(buf), 0);
}
//调用 cat 把服务器文件内容返回给浏览器
void serve_file(int client, const char *filename)
{
 FILE *resource = NULL;
 int numchars = 1;
 char buf[1024];
 //读取,丢弃头部
 buf[0] = 'A'; buf[1] = '\0';
 while ((numchars > 0) && strcmp("\n", buf))  /* read & discard headers */
  numchars = get_line(client, buf, sizeof(buf));
 resource = fopen(filename, "r");
 if (resource == NULL)
  not_found(client);//文件不存在,返回404错误
 else
 {
  headers(client, filename);//服务器向client发送响应头部信息,200
  cat(client, resource);//将文件中的信息发送到client
 }
 fclose(resource);
}

tinyhttpd服务器端的核心函数

python s ixusr_python d s的用法_python python

main函数

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)
   error_die("accept");
//创建工作线程,执行回调函数accept_request,参数client_sock  
 if (pthread_create(&newthread , NULL, accept_request,(void *)&client_sock) != 0)
   perror("pthread_create");
 }
//关闭套接字,就协议栈而言,即关闭TCP连接  
 close(server_sock);
 return(0);
}

服务器端套接字初始化设置:start_up

/*服务器端套接字初始化设置*/  
int startup(u_short *port)  
{  
    int httpd = 0;  
    struct sockaddr_in name;  
    httpd = socket(PF_INET, SOCK_STREAM, 0);//创建服务器端套接字  
    if (httpd == -1)  
        error_die("socket");  
    memset(&name, 0, sizeof(name));  
    name.sin_family = AF_INET;//地址簇  
    name.sin_port = htons(*port);//指定端口  
    name.sin_addr.s_addr = htonl(INADDR_ANY);//通配地址  
    if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0)//绑定到指定地址和端口  
        error_die("bind");  
    if (*port == 0)  /* if dynamically allocating a port *///动态分配一个端口  
    {  
        int namelen = sizeof(name);  
        /*在以端口号0调用bind后,getsockname用于返回由内核赋予的本地端口号*/  
        if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1)  
            error_die("getsockname");  
        *port = ntohs(name.sin_port);//网络字节顺序转换为主机字节顺序,返回主机字节顺序表达的数  
    }  
    if (listen(httpd, 5) < 0)//服务器客户端请求。套接字排队的最大连接个数5  
        error_die("listen");  
    return(httpd);  
}  

接收客户端的请求报文:accept_request

该函数结合前面的照片看,更容易理解

/* HTTP协议规定,请求从客户端发出,最后服务器端响应该请求并返回。 
 * 这是目前HTTP协议的规定,服务器不支持主动响应,所以目前的HTTP 
 * 协议版本都是基于客户端请求,然后响应的这种模型。 */  
 /*accept_request函数解析客户端请求,判断是请求静态文件还是cgi代码 
 (通过请求类型以及参数来判定),如果是静态文件则将文件输出给前端, 
 如果是cgi则进入cgi处理函数*/
void* accept_request(void* pclient)
{
 char buf[1024];
 int numchars;
 char method[255];
 char url[255];
 char path[512];
 size_t i, j;
 struct stat st;
 int cgi = 0;      /* becomes true if server decides this is a CGI
                    * program */
 char *query_string = NULL;
 int client = *(int*)pclient;
 //获取一行HTTP请求报文
 numchars = get_line(client, buf, sizeof(buf));
 i = 0; j = 0;
 //提取其中的方法post或get到method
 while (!ISspace(buf[j]) && (i < sizeof(method) - 1))
 {
  method[i] = buf[j];
  i++; j++;
 }
 method[i] = '\0';
 //tinyhttpd只实现了get post 方法
 if (strcasecmp(method, "GET") 0&& strcasecmp(method, "POST"))
 {
  unimplemented(client);
  return NULL;
 }
 //cgi为标志位,1表示开启CGI解析(POST方法)
 if (strcasecmp(method, "POST") == 0)
  cgi = 1;
 i = 0;
 //跳过method后面的空白字符
 while (ISspace(buf[j]) && (j < sizeof(buf)))
  j++;
//获取url
 while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf)))
 {
  url[i] = buf[j];
  i++; j++;
 }
 url[i] = '\0';
 //如果是get方法,url可能带?参数
 if (strcasecmp(method, "GET") == 0)
 {
  query_string = url;
  while ((*query_string != '?') && (*query_string != '\0'))
   query_string++;
  if (*query_string == '?')
  {
      //带参数需要执行cgi,解析参数
   cgi = 1;
   *query_string = '\0';
   query_string++;
  }
 }
//以上 将起始行 解析完毕
 sprintf(path, "htdocs%s", url);
 //如果path是一个目录,默认设置首页为index.html 
 if (path[strlen(path) - 1] == '/')
  strcat(path, "index.html");
//函数定义:    int stat(const char *file_name, struct stat *buf);
 //函数说明:    通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
 //返回值:     执行成功则返回0,失败返回-1,错误代码存于errno(需要include <errno.h>)
 if (stat(path, &st) == -1) {
     //访问的网页不存在,则不断的读取剩余的请求头部信息,并丢弃
  while ((numchars > 0) && strcmp("\n", buf))  /* read & discard headers */
   numchars = get_line(client, buf, sizeof(buf));
  not_found(client);
 }
 else
 {
    //访问你的网页存在则进行处理
    //S_IFDIR 判断是否为目录
  if ((st.st_mode & S_IFMT) == S_IFDIR)
   strcat(path, "/index.html");
  、
  //S_IXUSR:文件所有者具有可执行权限,
  //S_IXGRP:用户组具有可执行权限
  if ((st.st_mode & S_IXUSR) ||
      (st.st_mode & S_IXGRP) ||
      (st.st_mode & S_IXOTH)    )
   cgi = 1;
  if (!cgi)
    //将静态文件返回
   serve_file(client, path);
  else
   execute_cgi(client, path, method, query_string);
 }
//THHP协议是面向无连接的,所以要关闭
 close(client);
 return NULL;
}


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shumachanpin/article-121791-2.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    • 张云鹏
      张云鹏

      第四就把海警舰队扩

    热点图片
    拼命载入中...