这一次的Socket系列准备讲Web服务器。就是编写一个简单的Web服务器,具体怎么做呢?我也不是很清楚流程,所以我找来了一个开源的小的Web服务器--tinyhttpd。这个服务器才500多行的代码,使用C语言。这一小节就不讲别的内容了。就对这个程序进行一些注释和讲解了。
主函数:
1 int main(void) 2 { 3 int server_sock = -1; 4 u_short port = 0; 5 int client_sock = -1; 6 struct sockaddr_in client_name; 7 int client_name_len = sizeof(client_name); 8 pthread_t newthread; 9 10 server_sock = startup(&port);//Web服务器打开指定端口 11 printf("httpd running on port %d ", port); 12 13 while (1) 14 { 15 client_sock = accept(server_sock,(struct sockaddr *)&client_name,&client_name_len); 16 if (client_sock == -1) 17 error_die("accept"); 18 if (pthread_create(&newthread , NULL, accept_request, client_sock) != 0) 19 perror("pthread_create"); 20 } 21 close(server_sock); 22 return(0); 23 }
从主函数我们可以知道,这个服务器是对于每一个客户端的连接都采用一个线程对其处理。上面对应的startup函数是对指定的端口进行socket的创建,绑定,监听。
startup函数:
1 int startup(u_short *port) 2 { 3 int httpd = 0; 4 struct sockaddr_in name; 5 6 httpd = socket(PF_INET, SOCK_STREAM, 0); 7 if (httpd == -1) 8 error_die("socket"); 9 memset(&name, 0, sizeof(name)); 10 name.sin_family = AF_INET; 11 name.sin_port = htons(*port); 12 name.sin_addr.s_addr = htonl(INADDR_ANY); 13 if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0) 14 error_die("bind"); 15 if (*port == 0) /* if dynamically allocating a port */ 16 { 17 int namelen = sizeof(name); 18 if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1) 19 error_die("getsockname"); 20 *port = ntohs(name.sin_port); 21 } 22 if (listen(httpd, 5) < 0) 23 error_die("listen"); 24 return(httpd); 25 }
对于上面的getsockname函数是,如果传进来的port为0,那么就前面的bind就会失败,所以要使用getsockname函数来获取一个当前可用的可连接的Socket套接字的名字。此时返回的端口就是随机的。
接下来就是一个对每个客户端连接的处理函数
accept_request函数
1 void accept_request(int client) 2 { 3 char buf[1024]; 4 int numchars; 5 char method[255]; 6 char url[255]; 7 char path[512]; 8 size_t i, j; 9 struct stat st; 10 int cgi = 0; /* becomes true if server decides this is a CGI 11 * program */ 12 char *query_string = NULL; 13 14 numchars = get_line(client, buf, sizeof(buf));//获取第一行客户端的请求 GET / HTTP/1.1 类似这样的 15 i = 0; j = 0; 16 while (!ISspace(buf[j]) && (i < sizeof(method) - 1))//获取第一个单词,一般为GET或POST 两种请求方法 17 { 18 method[i] = buf[j]; 19 i++; j++; 20 } 21 method[i] = '