19.1 HTTP

19.1.1 无状态的Stateless协议

所谓的无状态也就是说,服务器响应客户端的请求之后,会断开连接。然后同样的客户端进行第二次请求,就会认为是一个新的连接

同样,为了弥补HTTP无法保持连接的缺点,Web编程中通常会使用CookieSession技术。

19.2 实现简单的Web服务器

19.2.1 实现基于Linux的多线程Web服务器

  1. //webserv_linux.c
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<unistd.h>
  5. #include<string.h>
  6. #include<arpa/inet.h>
  7. #include<sys/socket.h>
  8. #include<pthread.h>
  9. #define BUF_SIZE 1024
  10. #define SMALL_BUF 100
  11. void *request_handler(void *arg);
  12. void send_data(FILE *fp, char *ct, char *file_name);
  13. char *content_type(char *file);
  14. void send_error(FILE *fp);
  15. void error_handling(char *message);
  16. int main(int argc, char *argv[])
  17. {
  18. int serv_sock, clnt_sock;
  19. struct sockaddr_in serv_adr, clnt_adr;
  20. int clnt_adr_size;
  21. char buf[BUF_SIZE];
  22. pthread_t t_id;
  23. if(argc!=2){
  24. printf("Usage: %s<port>\n", argv[0]);
  25. exit(1);
  26. }
  27. serv_sock=socket(PF_INET, SOCK_STREAM, 0);
  28. memset(&serv_adr, 0, sizeof(serv_adr));
  29. serv_adr.sin_family=AF_INET;
  30. serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
  31. serv_adr.sin_port=htons(atoi(argv[1]));
  32. if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
  33. error_handling("bind() error");
  34. if(listen(serv_sock, 20)==-1)
  35. error_handling("listen() error");
  36. while(1)
  37. {
  38. clnt_adr_size=sizeof(clnt_adr);
  39. clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_size);
  40. printf("Connectiion Request: %s:%d\n", inet_ntoa(clnt_adr.sin_addr),ntohs(clnt_adr.sin_port));
  41. pthread_create(&t_id, NULL, request_handler, &clnt_sock);
  42. }
  43. close(serv_sock);
  44. return 0;
  45. }
  46. void *request_handler(void *arg)
  47. {
  48. int clnt_sock=*((int*)arg);
  49. char req_line[SMALL_BUF];
  50. FILE *clnt_read;
  51. FILE *clnt_write;
  52. char method[10];
  53. char ct[15];
  54. char file_name[30];
  55. clnt_read=fdopen(clnt_sock, "r");
  56. clnt_write=fdopen(dup(clnt_sock), "w");
  57. fgets(req_line, SMALL_BUF, clnt_read);
  58. if(strstr(req_line, "HTTP/")==NULL)
  59. {
  60. send_error(clnt_write);
  61. fclose(clnt_read);
  62. fclose(clnt_write);
  63. return 0;
  64. }
  65. strcpy(method, strtok(req_line, "/"));
  66. strcpy(file_name, strtok(NULL, "/"));
  67. strcpy(ct, content_type(file_name));
  68. if(strcmp(method, "GET")!=0)
  69. {
  70. send_error(clnt_write);
  71. fclose(clnt_read);
  72. fclose(clnt_write);
  73. return 0;
  74. }
  75. fclose(clnt_read);
  76. send_data(clnt_write, ct, file_name);
  77. }
  78. void send_data(FILE *fp, char *ct, char *file_name)
  79. {
  80. char protocol[]="HTTP/1.0 200 OK\r\n";
  81. char server[]="Server:Linux Web Server \r\n";
  82. char cnt_len[]="Content-length:2048\r\n";
  83. char cnt_type[SMALL_BUF];
  84. char buf[BUF_SIZE];
  85. FILE *send_file;
  86. sprintf(cnt_type, "Content-type:%s\r\n\r\n", ct);
  87. send_file=fopen(file_name, "r");
  88. if(send_file==NULL)
  89. {
  90. send_error(fp);
  91. return;
  92. }
  93. /*请传输头信息*/
  94. fputs(protocol, fp);
  95. fputs(server, fp);
  96. fputs(cnt_len, fp);
  97. fputs(cnt_type, fp);
  98. while(fgets(buf, BUF_SIZE, send_file)!=NULL)
  99. {
  100. fputs(buf, fp);
  101. fflush(fp);
  102. }
  103. fflush(fp);
  104. fclose(fp);
  105. }
  106. char *content_type(char *file)
  107. {
  108. char extension[SMALL_BUF];
  109. char file_name[SMALL_BUF];
  110. strcpy(file_name, file);
  111. strtok(file_name, ".");
  112. strcpy(extension, strtok(NULL, "."));
  113. if(!strcmp(extension, "html")||!strcmp(extension,"htm"))
  114. return "text/html";
  115. else
  116. return "text/plain";
  117. }
  118. void send_error(FILE *fp)
  119. {
  120. char protocol[]="HTTP/1.0 400 Bad Request\r\n";
  121. char server[]="Server:Linux Web Server\r\n";
  122. char cnt_len[]="Content-length:2048\r\n";
  123. char cnt_type[]="Conntent-type:text/html\r\n\r\n";
  124. char content[]="<html><head><title>NETWORK</title></head>"
  125. "<body><font size=+5><br>发生错误!查看请求文件名和请求方式!"
  126. "</font></body></html>";
  127. fputs(protocol, fp);
  128. fputs(server, fp);
  129. fputs(cnt_len, fp);
  130. fputs(cnt_type, fp);
  131. fflush(fp);
  132. }
  133. void error_handling(char *message)
  134. {
  135. fputs(message, stderr);
  136. fputc('\n', stderr);
  137. exit(1);
  138. }