va_start&strcat&strstr

本文详细解释了C语言中va_list、va_start和va_end宏的使用方法,并通过实例展示了如何利用这些宏来处理可变数量的参数。此外,还介绍了strstr和strcat等字符串操作函数的基本用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.va_start&va_arg& va_end  

int   sprintf   (char   *   szBuffer,   const   char   *   szFormat,   ...)  
  {  
            int           iReturn   ;  
            va_list   pArgs   ;  
   
            va_start   (pArgs,   szFormat)   ;//??  
            iReturn   =   vsprintf   (szBuffer,   szFormat,   pArgs)   ;  
            va_end   (pArgs)   ;  
   
            return   iReturn   ;  
  }  
  va_list,va_start,va_end为何意?  
      注:vsprintf的前俩个参数与sprintf相同:保存结果的字符缓冲区和  
  格式字符串,第三个:指向格式化参数数组的指针。

-----------------------------------------------------------------

取得可变参数的,可以参考一下msdn上的这个例子  
  Example  
   
  /*   VA.C:   The   program   below   illustrates   passing   a   variable  
    *   number   of   arguments   using   the   following   macros:  
    *             va_start                         va_arg                             va_end  
    *             va_list                           va_dcl   (UNIX   only)  
    */  
   
  #include   <stdio.h>  
  #define   ANSI                         /*   Comment   out   for   UNIX   version           */  
  #ifdef   ANSI                           /*   ANSI   compatible   version                     */  
  #include   <stdarg.h>  
  int   average(   int   first,   ...   );  
  #else                                       /*   UNIX   compatible   version                     */  
  #include   <varargs.h>  
  int   average(   va_list   );  
  #endif  
   
  void   main(   void   )  
  {  
        /*   Call   with   3   integers   (-1   is   used   as   terminator).   */  
        printf(   "Average   is:   %d/n",   average(   2,   3,   4,   -1   )   );  
   
        /*   Call   with   4   integers.   */  
        printf(   "Average   is:   %d/n",   average(   5,   7,   9,   11,   -1   )   );  
   
        /*   Call   with   just   -1   terminator.   */  
        printf(   "Average   is:   %d/n",   average(   -1   )   );  
  }  
   
  /*   Returns   the   average   of   a   variable   list   of   integers.   */  
  #ifdef   ANSI                           /*   ANSI   compatible   version         */  
  int   average(   int   first,   ...   )  
  {  
        int   count   =   0,   sum   =   0,   i   =   first;  
        va_list   marker;  
   
        va_start(   marker,   first   );           /*   Initialize   variable   arguments.   */  
        while(   i   !=   -1   )  
        {  
              sum   +=   i;  
              count++;  
              i   =   va_arg(   marker,   int);  
        }  
        va_end(   marker   );                             /*   Reset   variable   arguments.             */  
        return(   sum   ?   (sum   /   count)   :   0   );  
  }  
  #else               /*   UNIX   compatible   version   must   use   old-style   definition.     */  
  int   average(   va_alist   )  
  va_dcl  
  {  
        int   i,   count,   sum;  
        va_list   marker;  
   
        va_start(   marker   );                         /*   Initialize   variable   arguments.   */  
        for(   sum   =   count   =   0;   (i   =   va_arg(   marker,   int))   !=   -1;   count++   )  
              sum   +=   i;  
        va_end(   marker   );                             /*   Reset   variable   arguments.             */  
        return(   sum   ?   (sum   /   count)   :   0   );  
  }  
  #endif  
   
   
  Output  
   
  Average   is:   3  
  Average   is:   8  
  Average   is:   0  
   
   
  更多的看看msdn 

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

2.strstr(a,b)求子字符串b在a中出现的位置;

strcat(a,b)将字符串b拼接到字符串a的后面;

我用多线程编写了一个webserver,帮我分析并优化一下: /* Copyright(c) 2008-2024 ChengDu TP-LINK Technologies Co.Ltd. * * file multi_thread.c * brief Construct a webserver using a multi-thread approach * author Wang Junhang * version 0.0.0 * date 2025-08-07 * * history */ /************************************Include Files**********************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> #include <signal.h> #include <time.h> /***********************************************************************************/ /* DEFINES */ /***********************************************************************************/ #define PORT 8080 /* Socket Port */ #define WEB_ROOT "./www" /* Server root directory */ #define BUFFER_SIZE 1024 #define MAX_SOCKET_CONN 10 /*Maximum number of socket connections*/ #define LOG_FILE_NAME "multi_thread.log" /***********************************************************************************/ /* TYPES */ /***********************************************************************************/ /***********************************************************************************/ /* EXTERN_PROTOTYPES */ /***********************************************************************************/ /***********************************************************************************/ /* LOCAL_PROTOTYPES */ /***********************************************************************************/ /***********************************************************************************/ /* VARIABLES */ /***********************************************************************************/ FILE *log_file; /* Global variable for log file pointer */ int server_socket; /* Global server socket file descriptor */ time_t now; /* Global time */ struct tm *tm_info; /***********************************************************************************/ /* LOCAL_FUNCTIONS */ /***********************************************************************************/ /***********************************************************************************/ /* PUBLIC_FUNCTIONS */ /***********************************************************************************/ void *handle_request(void *socket_ptr); void send_response_header(int socket, int status, char *content_type); void init_log(const char *log_filename); void close_log(); void signal_handler(int sig); void cleanup(); /***********************************************************************************/ /* GLOBAL_FUNCTIONS */ /***********************************************************************************/ int main() { signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGTSTP, signal_handler); init_log(LOG_FILE_NAME); int client_socket; struct sockaddr_in address; int addrlen = sizeof(address); if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("Socket creation failed"); exit(EXIT_FAILURE); } /* Forcefully attaching socket to the defined port */ address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_socket, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("Bind failed"); exit(EXIT_FAILURE); } if (listen(server_socket, MAX_SOCKET_CONN) < 0) { perror("Listen failed"); exit(EXIT_FAILURE); } printf("Server listening on port %d\n", PORT); fprintf(log_file, "Server listening on port %d\n\r\n", PORT); /* recording start to log */ /* Accept incoming connections and handle in separate threads */ while (1) { if ((client_socket = accept(server_socket, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { perror("Accept failed"); exit(EXIT_FAILURE); } /* Create a new thread to handle the client */ pthread_t thread; int *socket_ptr = malloc(sizeof(int)); *socket_ptr = client_socket; if (pthread_create(&thread, NULL, handle_request, (void *)socket_ptr) < 0) { perror("Thread creation failed"); exit(EXIT_FAILURE); } pthread_detach(thread); /* Detach the thread to avoid memory leaks */ } cleanup(); return 0; } /* * fn void *handle_request(void *socket_ptr) * brief Respond to HTTP requests based on different request methods (GET/POST/OTHERS). * details * param[in] socket_ptr The pointer of connected socket * * return NULL * retval NULL * * note */ void *handle_request(void *socket_ptr) { int client_socket = *((int *)socket_ptr); free(socket_ptr); /* release the pointer of client socket*/ int read_size; char buffer[BUFFER_SIZE] = {0}; char method[10], path[255], protocol[20]; read_size = read(client_socket, buffer, sizeof(buffer)); if (read_size <= 0) { perror("Read failed"); return; } fprintf(log_file, "Request received:\n%s\r\n", buffer); /* recording request to log */ if (strstr(buffer, "GET") != NULL) { sscanf(buffer, "%s %s %s", method, path, protocol); printf("Received request:\n%s\n", buffer); if (strcmp(path, "/") == 0) { char tmp_path_1[64], tmp_path_2[64]; snprintf(tmp_path_1, sizeof(tmp_path_1), "%s%s", WEB_ROOT, "/index.html"); snprintf(tmp_path_2, sizeof(tmp_path_1), "%s%s", WEB_ROOT, "/Index.html"); if (access(tmp_path_1, F_OK) != -1) { sprintf(path, "/index.html"); } else if (access(tmp_path_2, F_OK) != -1) { sprintf(path, "/Index.html"); } else { } } /* Construct full file path (prepend ./www) */ char full_path[256]; snprintf(full_path, sizeof(full_path), "%s%s", WEB_ROOT, path); int file_fd = open(full_path, O_RDONLY); if (file_fd == -1) { fprintf(log_file, "Error opening file: %s\r\n", full_path); char *content_type = "text/html"; char *content = "<h1>404 Not Found</h1>"; send_response_header(client_socket, 404, content_type); send(client_socket, content, strlen(content), 0); } else { off_t file_size = lseek(file_fd, 0, SEEK_END); lseek(file_fd, 0, SEEK_SET); printf("Content is:%d:\r\n", file_size); char *content_type = "text/html"; if (strstr(full_path, ".png")) content_type = "image/png"; if (strstr(full_path, ".jpg")) content_type = "image/jpeg"; if (strstr(full_path, ".gif")) content_type = "image/gif"; if (strstr(full_path, ".html")) content_type = "text/html"; if (strstr(full_path, ".css")) content_type = "text/css"; if (strstr(full_path, ".json")) content_type = "text/javascript"; if (strstr(full_path, ".js")) content_type = "text/javascript"; send_response_header(client_socket, 200, content_type); /* Send response content */ char send_buffer[BUFFER_SIZE]; ssize_t bytes_read; while ((bytes_read = read(file_fd, send_buffer, BUFFER_SIZE)) > 0) { write(client_socket, send_buffer, bytes_read); } close(file_fd); fprintf(log_file, "Response file: %s\r\n", full_path); } } else if (strstr(buffer, "POST") != NULL) { /* Handle POST requests */ char *content_length_header = strstr(buffer, "Content-Length:"); int content_length = 0; if (content_length_header != NULL) { content_length = atoi(content_length_header + 15); // Skip "Content-Length:" to get the value } /* Read POST data */ char post_content_buffer[BUFFER_SIZE] = {0}; int total_read = 0; while ((read_size = recv(client_socket, post_content_buffer, 1024, 0)) > 0) { total_read += read_size; if (total_read >= content_length) { break; } } printf("Post data is:\r\n%s:\r\n\r\n", post_content_buffer); fprintf(log_file, "Post data is: %s\r\n", post_content_buffer); /* Process the received data (in buffer) Here, you can handle the POST data according to your application's logic For simplicity, we just send a response indicating the data was received*/ /* Send Response for POST request */ char *content_type = "text/html"; char *content = "<h1> Post Response</h1>"; send_response_header(client_socket, 200, content_type); send(client_socket, content, strlen(content), 0); } else { /* Send Error Response */ char *content_type = "text/html"; char *content = "<h1>500 Internal Server Error</h1>"; send_response_header(client_socket, 500, content_type); send(client_socket, content, strlen(content), 0); fprintf(log_file, "500 Sever can't serve this type of request\r\n"); /* recording error to log */ } close(client_socket); /* close the client socket file describer*/ return NULL; } /* * fn void send_response_header(int socket, int status, char *content_type) * brief Send the response header to the client * details * param[in] socket The file describer of connected socket * param[in] status Http response status * param[in] content_type The type of response * * param[out] None None * * return None * retval None None * * note */ void send_response_header(int socket, int status, char *content_type) { char response[BUFFER_SIZE] = {0}; char headers[BUFFER_SIZE] = {0}; sprintf(headers, "HTTP/1.1 %d ", status); switch (status) { case 200: strcat(headers, "OK\r\n"); break; case 404: strcat(headers, "Not Found\r\n"); break; default: strcat(headers, "Internal Server Error\r\n"); } /* Send HTTP response header */ sprintf(response, "%sContent-Type: %s\r\n\r\n", headers, content_type); send(socket, response, strlen(response), 0); } /* * brief init the log file */ void init_log(const char *log_filename) { log_file = fopen(log_filename, "a"); if (log_file == NULL) { perror("Error opening log file"); exit(EXIT_FAILURE); } time(&now); tm_info = localtime(&now); fprintf(log_file, "=== Server started ===\n"); fprintf(log_file, "Current time: %s", asctime(tm_info)); } /* * brief close the log file */ void close_log() { time(&now); tm_info = localtime(&now); fprintf(log_file, "Current time: %s", asctime(tm_info)); fprintf(log_file, "=== Server closed ===\n\r\n"); fclose(log_file); } /* * brief process exit signal */ void signal_handler(int sig) { printf("\rCaught signal %d, exiting...\n", sig); fprintf(log_file, "Caught signal %d, exiting...\n", sig); cleanup(); exit(0); } /* * brief clean all resources */ void cleanup() { close(server_socket); close_log(); }
08-09
#include <stdio.h> #include <stdbool.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <ctype.h> #include <strings.h> #include <string.h> #include <sys/stat.h> #include <pthread.h> #include <sys/wait.h> #include <stdlib.h> // 宏定义,是否是空格 #define ISspace(x) isspace((int)(x)) #define SERVER_STRING "Server: jdbhttpd/0.1.0\r\n" // 每次收到请求,创建一个线程来处理接受到的请求 // 把client_sock转成地址作为参数传入pthread_create void accept_request(void *arg); void bad_request(int); void cat(int, FILE *); void cannot_execute(int); void error_die(const char *); void execute_cgi(int, const char *, const char *, const char *); int get_line(int, char *, int); // 返回http头 void headers(int, const char *); void not_found(int); void serve_file(int, const char *); int startup(u_short *); void unimplemented(int); void normalize_path(char *path) { char *p = path; char *q = path; while (*p) { if (strncmp(p, "/../", 4) == 0) { p += 3; while (q > path && *--q != '/') ; } else if (strncmp(p, "/./", 3) == 0) { p += 2; } else if (strncmp(p, "//", 2) == 0) { p += 1; } else { *q++ = *p++; } } *q = '\0'; } /**********************************************************************/ /* A request has caused a call to accept() on the server port to * return. Process the request appropriately. * Parameters: the socket connected to the client */ /**********************************************************************/ void accept_request(void *arg) { int client = (intptr_t)arg; char buf[1024]; char method[255]; char url[255]; char path[512]; struct stat st; int cgi = 0; char *query_string = NULL; int numchars = get_line(client, buf, sizeof(buf)); size_t i = 0; size_t j = 0; while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { method[i] = buf[j]; i++; j++; } method[i] = '\0'; /* 判断是Get还是Post,否则501 Not Implemented */ if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) { unimplemented(client); return; } /* 如果是POST,cgi置为1 */ if (strcasecmp(method, "POST") == 0) { cgi = 1; } i = 0; while (ISspace(buf[j]) && (j < sizeof(buf))) { j++; } while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { url[i] = buf[j]; i++; j++; } url[i] = '\0'; /* 判断Get请求 */ if (strcasecmp(method, "GET") == 0) { query_string = url; while ((*query_string != '?') && (*query_string != '\0')) query_string++; if (*query_string == '?') { cgi = 1; *query_string = '\0'; query_string++; } } // 路径 sprintf(path, "htdocs%s", url); // 默认地址,解析到的路径如果为/,则自动加上index.html if (path[strlen(path) - 1] == '/') strcat(path, "Index.html"); // 获得文件信息 if (stat(path, &st) == -1) { // 把所有http信息读出然后丢弃 while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); // 没有找到 not_found(client); } else { if ((st.st_mode & S_IFMT) == S_IFDIR) strcat(path, "/Index.html"); // 如果你的文件默认是有执行权限的,自动解析成cgi程序,如果有执行权限但是不能执行,会接受到报错信号 if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH)) cgi = 1; if (!cgi) // 接读取文件返回给请求的http客户端 serve_file(client, path); else // 执行cgi文件 execute_cgi(client, path, method, query_string); } // 执行完毕关闭socket close(client); } /**********************************************************************/ /* Inform the client that a request it has made has a problem. * Parameters: client socket */ /**********************************************************************/ void bad_request(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n"); send(client, buf, sizeof(buf), 0); sprintf(buf, "Content-type: text/html\r\n"); send(client, buf, sizeof(buf), 0); sprintf(buf, "\r\n"); send(client, buf, sizeof(buf), 0); sprintf(buf, "<P>Your browser sent a bad request, "); send(client, buf, sizeof(buf), 0); sprintf(buf, "such as a POST without a Content-Length.\r\n"); send(client, buf, sizeof(buf), 0); } /*! * @brief 将文件内容发送到网络客户端 * * @param[in] client 客户端套接字描述符 * @param[in] resource 文件指针(指向要发送的文件) */ void cat(int client, FILE *resource) { char buf[1024]; size_t bytes_read; while ((bytes_read = fread(buf, 1, sizeof(buf), resource)) > 0) { if (send(client, buf, bytes_read, 0) < bytes_read) { perror("send"); break; } } } /**********************************************************************/ /* Inform the client that a CGI script could not be executed. * Parameter: the client socket descriptor. */ /**********************************************************************/ void cannot_execute(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 500 Internal Server Error\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-type: text/html\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "<P>Error prohibited CGI execution.\r\n"); send(client, buf, strlen(buf), 0); } /**********************************************************************/ /* Print out an error message with perror() (for system errors; based * on value of errno, which indicates system call errors) and exit the * program indicating an error. */ /**********************************************************************/ void error_die(const char *sc) { perror(sc); exit(1); } /**********************************************************************/ /* Execute a CGI script. Will need to set environment variables as * appropriate. * Parameters: client socket descriptor * path to the CGI script */ /**********************************************************************/ void execute_cgi(int client, const char *path, const char *method, const char *query_string) { // 缓冲区 char buf[1024]; int cgi_output[2]; int cgi_input[2]; pid_t pid; int status; int i = 0; char c; int numchars = 1; int content_length = -1; // 默认字符 buf[0] = 'A'; buf[1] = '\0'; // 忽略大小写比较字符串 if (strcasecmp(method, "GET") == 0) while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); else /* POST */ { numchars = get_line(client, buf, sizeof(buf)); while ((numchars > 0) && strcmp("\n", buf)) { // 如果是POST请求,就需要得到Content-Length,Content-Length:这个字符串一共长为15位,所以 // 取出头部一句后,将第16位设置结束符,进行比较 // 第16位置为结束 buf[15] = '\0'; if (strcasecmp(buf, "Content-Length:") == 0) // 内存从第17位开始就是长度,将17位开始的所有字符串转成整数就是content_length content_length = atoi(&(buf[16])); numchars = get_line(client, buf, sizeof(buf)); } if (content_length == -1) { bad_request(client); return; } } sprintf(buf, "HTTP/1.0 200 OK\r\n"); send(client, buf, strlen(buf), 0); // 建立output管道 if (pipe(cgi_output) < 0) { cannot_execute(client); return; } // 建立input管道 if (pipe(cgi_input) < 0) { cannot_execute(client); return; } if ((pid = fork()) < 0) { cannot_execute(client); return; } if (pid == 0) /* child: CGI script */ { char meth_env[255]; char query_env[255]; char length_env[255]; // 子进程输出重定向到output管道的1端 dup2(cgi_output[1], 1); // 子进程输入重定向到input管道的0端 dup2(cgi_input[0], 0); // 关闭无用管道口 close(cgi_output[0]); close(cgi_input[1]); // CGI环境变量 sprintf(meth_env, "REQUEST_METHOD=%s", method); putenv(meth_env); if (strcasecmp(method, "GET") == 0) { sprintf(query_env, "QUERY_STRING=%s", query_string); putenv(query_env); } else { /* POST */ sprintf(length_env, "CONTENT_LENGTH=%d", content_length); putenv(length_env); } // 替换执行path execl(path, path, NULL); // int m = execl(path, path, NULL); // 如果path有问题,例如将html网页改成可执行的,但是执行后m为-1 // 退出子进程,管道被破坏,但是父进程还在往里面写东西,触发Program received signal SIGPIPE, Broken pipe. exit(0); } else { /* parent */ close(cgi_output[1]); close(cgi_input[0]); if (strcasecmp(method, "POST") == 0) for (i = 0; i < content_length; i++) { recv(client, &c, 1, 0); ssize_t bytes_written = write(cgi_input[1], &c, 1); if (bytes_written <= 0) { // 错误处理 perror("Failed to write to CGI"); close(cgi_input[1]); close(cgi_input[0]); break; } } // 从output管道读到子进程处理后的信息,然后send出去 while (read(cgi_output[0], &c, 1) > 0) send(client, &c, 1, 0); // 完成操作后关闭管道 close(cgi_output[0]); close(cgi_input[1]); // 等待子进程返回 waitpid(pid, &status, 0); } } /**********************************************************************/ /* Get a line from a socket, whether the line ends in a newline, * carriage return, or a CRLF combination. Terminates the string read * with a null character. If no newline indicator is found before the * end of the buffer, the string is terminated with a null. If any of * the above three line terminators is read, the last character of the * string will be a linefeed and the string will be terminated with a * null character. * Parameters: the socket descriptor * the buffer to save the data in * the size of the buffer * Returns: the number of bytes stored (excluding null) */ /**********************************************************************/ // 得到一行数据,只要发现c为\n,就认为是一行结束,如果读到\r,再用MSG_PEEK的方式读入一个字符,如果是\n,从socket用读出 // 如果是下个字符则不处理,将c置为\n,结束。如果读到的数据为0中断,或者小于0,也视为结束,c置为\n int get_line(int sock, char *buf, int size) { int i = 0; char c = '\0'; int n; while ((i < size - 1) && (c != '\n')) { n = recv(sock, &c, 1, 0); /* DEBUG printf("%02X\n", c); */ if (n > 0) { if (c == '\r') { // 偷窥一个字节,如果是\n就读走 n = recv(sock, &c, 1, MSG_PEEK); /* DEBUG printf("%02X\n", c); */ if ((n > 0) && (c == '\n')) recv(sock, &c, 1, 0); else // 不是\n(读到下一行的字符)或者没读到,置c为\n 跳出循环,完成一行读取 c = '\n'; } buf[i] = c; i++; } else c = '\n'; } buf[i] = '\0'; return (i); } /**********************************************************************/ /* Return the informational HTTP headers about a file. */ /* Parameters: the socket to print the headers on * the name of the file */ /**********************************************************************/ // 加入http的headers const char *get_content_type(const char *path) { const char *ext = strrchr(path, '.'); if (ext) { if (strcasecmp(ext, ".css") == 0) return "text/css"; if (strcasecmp(ext, ".js") == 0) return "application/javascript"; if (strcasecmp(ext, ".png") == 0) return "image/png"; if (strcasecmp(ext, ".jpg") == 0 || strcasecmp(ext, ".jpeg") == 0) return "image/jpeg"; if (strcasecmp(ext, ".gif") == 0) return "image/gif"; if (strcasecmp(ext, ".ico") == 0) return "image/x-icon"; if (strcasecmp(ext, ".svg") == 0) return "image/svg+xml"; if (strcasecmp(ext, ".woff") == 0) return "font/woff"; if (strcasecmp(ext, ".woff2") == 0) return "font/woff2"; } return "text/html"; } /*! * @brief * * @param[in] client Comment * @param[in] filename Comment */ void headers(int client, const char *filename) { char buf[1024]; const char *content_type = get_content_type(filename); sprintf(buf, "HTTP/1.0 200 OK\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, SERVER_STRING); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-Type: %s\r\n", content_type); send(client, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(client, buf, strlen(buf), 0); } /*! * @brief * * @param[in] client Comment */ void not_found(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, SERVER_STRING); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-Type: text/html\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "<HTML><TITLE>Not Found</TITLE>\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "<BODY><P>The server could not fulfill\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "your request because the resource specified\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "is unavailable or nonexistent.\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "</BODY></HTML>\r\n"); send(client, buf, strlen(buf), 0); } /**********************************************************************/ /* Send a regular file to the client. Use headers, and report * errors to client if they occur. * Parameters: a pointer to a file structure produced from the socket * file descriptor * the name of the file to serve */ /**********************************************************************/ /*! * @brief 如果不是CGI文件,直接读取文件返回给请求的http客户端 * * @param[in] client Comment * @param[in] filename Comment */ 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, "rb"); printf("Serving file: %s\n", filename); if (resource == NULL) { not_found(client); } else { headers(client, filename); cat(client, resource); } fclose(resource); } /**********************************************************************/ /* This function starts the process of listening for web connections * on a specified port. If the port is 0, then dynamically allocate a * port and modify the original port variable to reflect the actual * port. * Parameters: pointer to variable containing the port to connect on * Returns: the socket */ /**********************************************************************/ 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); // 绑定socket if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0) { error_die("bind"); } // 如果端口没有设置,提供个随机端口 if (*port == 0) /* if dynamically allocating a port */ { socklen_t namelen = sizeof(name); if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1) { error_die("getsockname"); } *port = ntohs(name.sin_port); } // 监听 if (listen(httpd, 5) < 0) error_die("listen"); return (httpd); } /**********************************************************************/ /* Inform the client that the requested web method has not been * implemented. * Parameter: the client socket */ /**********************************************************************/ // 如果方法没有实现,就返回此信息 void unimplemented(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, SERVER_STRING); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-Type: text/html\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "</TITLE></HEAD>\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "<BODY><P>HTTP request method not supported.\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "</BODY></HTML>\r\n"); send(client, buf, strlen(buf), 0); } /**********************************************************************/ int main(void) { int server_sock = -1; u_short port = 80; int client_sock = -1; struct sockaddr_in client_name; // 这边要为socklen_t类型 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"); } // 每次收到请求,创建一个线程来处理接受到的请求 // 把client_sock转成地址作为参数传入pthread_create if (pthread_create(&newthread, NULL, (void *)accept_request, (void *)(intptr_t)client_sock) != 0) { perror("pthread_create"); } } close(server_sock); return (0); } 修改代码实现以多线程方式实现web server功能(必修)
08-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值