Chinaunix首页 | 论坛 | 博客
  • 博客访问: 867919
  • 博文数量: 82
  • 博客积分: 2283
  • 博客等级: 大尉
  • 技术积分: 2007
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-15 22:19
文章分类

全部博文(82)

文章存档

2012年(82)

分类: 系统运维

2012-10-05 21:19:53

这个版本还不是很完善,但Web服务器的基本框架已经出 来了,还有部分的功能需要进行进一步的测试和修改。虽然说C的开发比较慢,对于程序员来说比较难以操作,但通过用C写这些很底层的东西,可以更好的了解的 象java的socket中的工作原理。有一定的帮助!
 
以下是源代码:
  1. /**************filename: Server.cpp**************** 
  2.  该程序通过标准socket实现简单Http服务器 
  3.  运行该服务器可以通过浏览器访问服务器目录下的 
  4.  Html文件和jpg图片 完成初步的Http服务器功能 
  5. ***************************************************/  
  6. #include   
  7. #include   
  8. #include   
  9. using namespace std;  
  10. #define SERVER_PORT 10000         //自定义的服务端口  
  11. #define HOSTLEN 256           //主机名长度  
  12. #define BACKLOG 10           //同时等待的连接个数  
  13. /************************************** 
  14.  该方法包装了send() 
  15.  通过该方法发送数据 能够全部发出 
  16.  没有遗漏 
  17. **************************************/  
  18. int sendall(int s, char *buf, int *len) {  
  19.  int total = 0;           // 已经发送字节数  
  20.  int bytesleft = *len;                                   //还剩余多少字节  
  21.  int n;  
  22.  while(total < *len) {  
  23.   n = send(s, buf+total, bytesleft, 0);  
  24.   if (n == -1) { break; }  
  25.   total += n;  
  26.   bytesleft -= n;  
  27.  }  
  28.  *len = total;           // 返回实际发送出去的字节数  
  29.  return n==-1?-1:0;          // 成功发送返回0 失败-1  
  30. }  
  31. /************************************** 
  32.  该方法处理错误请求 
  33.  并向客户端发送错误信息 
  34. **************************************/  
  35. void wrong_req(int sock) {  
  36.  char* error_head = "HTTP/1.0 501 Not Implemented\r\n"//输出501错误  
  37.  int len = strlen(error_head);  
  38.  if (sendall(sock, error_head, &len) == -1) {   //向客户发送  
  39.   printf("Sending failed!");  
  40.   return;  
  41.  }        
  42.  char* error_type = "Content-type: text/plain\r\n";    
  43.  len = strlen(error_type);  
  44.  if (sendall(sock, error_type, &len) == -1) {  
  45.   printf("Sending failed!");  
  46.   return;  
  47.  }  
  48.  char* error_end = "\r\n";  
  49.  len = strlen(error_end);  
  50.  if (sendall(sock, error_end, &len) == -1) {  
  51.   printf("Sending failed!");  
  52.   return;  
  53.  }  
  54.  char* prompt_info = "The command is not yet completed\r\n";  
  55.  len = strlen(prompt_info);  
  56.  if (sendall(sock, prompt_info, &len) == -1) {  
  57.   printf("Sending failed!");  
  58.   return;  
  59.  }  
  60. }  
  61. /********************************** 
  62.  该方法判断用户请求的文件是否存在 
  63.  不存在返回true 存在返回false 
  64. ***********************************/  
  65. bool not_exit(char* arguments) {  
  66.  struct stat dir_info;  
  67.  return (stat(arguments, &dir_info) == -1);  
  68. }  
  69. /************************************* 
  70.  所请求的文件不存在 
  71. *************************************/  
  72. void file_not_found(char* arguments, int sock) {  
  73.  char* error_head = "HTTP/1.0 404 Not Found\r\n";   //构造404错误head  
  74.  int len = strlen(error_head);  
  75.  if (sendall(sock, error_head, &len) == -1) {    //向客户端发送  
  76.   printf("Sending error!");  
  77.   return;  
  78.  }     
  79.  char* error_type = "Content-type: text/plain\r\n";  
  80.  len = strlen(error_type);  
  81.  if (sendall(sock, error_type, &len) == -1) {  
  82.   printf("Sending error!");  
  83.   return;  
  84.  }  
  85.  char* error_end = "\r\n";  
  86.  len = strlen(error_end);  
  87.  if (sendall(sock, error_end, &len) == -1) {  
  88.   printf("Sending error!");  
  89.   return;  
  90.  }  
  91.  char prompt_info[50] = "Not found:  ";  
  92.  strcat(prompt_info, arguments);  
  93.  len = strlen(prompt_info);  
  94.  if (sendall(sock, prompt_info, &len) == -1) {    //输出未找到的文件  
  95.   printf("Sending error!");  
  96.   return;  
  97.  }      
  98. }  
  99. /************************************* 
  100.  发送Http协议头部信息 
  101.  其中包括响应类型和Content Type 
  102. *************************************/  
  103. void send_header(int send_to, char* content_type) {  
  104.    
  105.  char* head = "HTTP/1.0 200 OK\r\n";     //正确的头部信息  
  106.  int len = strlen(head);  
  107.  if (sendall(send_to, head, &len) == -1) {   //向连接的客户端发送数据  
  108.   printf("Sending error");  
  109.   return;  
  110.  }  
  111.  if (content_type) {         //content_type不为空  
  112.   char temp_1[30] = "Content-type: ";    //准备好要连接的字串  
  113.   strcat(temp_1, content_type);     //构造content_type  
  114.   strcat(temp_1, "\r\n");  
  115.   len = strlen(temp_1);  
  116.   if (sendall(send_to, temp_1, &len) == -1) {  
  117.    printf("Sending error!");  
  118.    return;  
  119.   }  
  120.  }  
  121. }  
  122. /*********************************** 
  123.  取得用户所请求的文件类型 
  124.  即文件后缀 (.html .jpg .gif) 
  125. ************************************/  
  126. char* file_type(char* arg) {  
  127.  char * temp;          //临时字符串指针  
  128.  if ((temp=strrchr(arg,'.')) != NULL) {    //取得后缀  
  129.   return temp+1;  
  130.  }  
  131.  return "";           //如果请求的文件名中没有. 则返回空串  
  132. }  
  133. /************************************* 
  134.  该方法为程序核心 
  135.  负责真正发送文件 如*.html *.jpg等 
  136. *************************************/  
  137. void send_file(char* arguments, int sock) {  
  138.  char* extension = file_type(arguments);    //获得文件后缀名  
  139.  char* content_type = "text/plain";     //初始化type='text/plain'  
  140.  FILE* read_from;         //本地文件指针 从该文件中读取.html .jpg等  
  141.  int readed = -1;         //每次读得的字节数  
  142.    
  143.  if (strcmp(extension, "html") == 0) {    //发送内容为html  
  144.   content_type = "text/html";  
  145.  }  
  146.  if (strcmp(extension, "gif") == 0) {    //发送内容为gif  
  147.   content_type = "image/gif";  
  148.  }  
  149.  if (strcmp(extension, "jpg") == 0) {    //发送内容为jpg  
  150.   content_type = "image/jpg";  
  151.  }  
  152.  read_from = fopen(arguments, "r");     //打开用户指定的文件 准备读取  
  153.  if(read_from != NULL) {        //指针不为空  
  154.   char read_buf[128];        //读文件时的字节缓存数组  
  155.   send_header(sock, content_type);    //发送协议头  
  156.   send(sock, "\r\n", 2, 0);      //再加一个"\r\n" 不能缺少 格式要求  
  157.   while(!feof(read_from)) {      //判断文件是否已经结束  
  158.    fgets(read_buf, 128, read_from);   //读取  
  159.    int len = strlen(read_buf);  
  160.    if (sendall(sock, read_buf, &len) == -1) { //发送数据  
  161.     printf("Sending error!");    //出现发送错误 显示到控制台 继续发送  
  162.     continue;  
  163.    }  
  164.   }  
  165.  }  
  166. }  
  167. /*********************************** 
  168.  解析并处理用户请求 
  169. ***********************************/  
  170. void handle_req(char* request, int client_sock) {  
  171.  char command[BUFSIZ];        //保存解析到的命令字段 GET PUT  
  172.  char arguments[BUFSIZ];        //保存解析到的请求的文件  
  173.  /* 
  174.   * 在用户请求前加上当前目录符号 
  175.   */  
  176.  strcpy(arguments, "./");       //注意该符号在不同操作系统的区别  
  177.  /* 
  178.   * 解析请求 
  179.   */  
  180.  if (sscanf(request, "%s%s", command, arguments+2) != 2) {  
  181.   return;           //解析出错在返回  
  182.  }  
  183.    
  184.  printf("handle_cmd:    %s\n",command);    //向控制台输出此时的命令  
  185.  printf("handle_path:   %s\n",arguments);   //向控制台输出此时的请求路径  
  186.    
  187.  if (strcmp(command, "GET") != 0) {     //请求命令格式是否正确  
  188.   wrong_req(client_sock);  
  189.   return;  
  190.  }  
  191.  if (not_exit(arguments)) {       //请求的文件是否存在    
  192.   file_not_found(arguments, client_sock);  
  193.   return;  
  194.  }  
  195.  send_file(arguments, client_sock);     //命令格式及请求路径正确则发送数据  
  196.    
  197.  return;  
  198. }  
  199. /************************************* 
  200.  该方法构造服务器端的SOCKET 
  201.  返回构造好的socket描述符 
  202. *************************************/  
  203. int make_server_socket() {  
  204.  struct sockaddr_in server_addr;       //服务器地址结构体  
  205.  int tempSockId;           //临时存储socket描述符  
  206.  tempSockId = socket(PF_INET, SOCK_STREAM, 0);  
  207.    
  208.  if (tempSockId == -1) {         //如果返回值为-1 则出错  
  209.   return -1;  
  210.  }  
  211.  /* 
  212.   * 填充服务器连接信息 
  213.   */  
  214.  server_addr.sin_family = AF_INET;  
  215.  server_addr.sin_port = htons(SERVER_PORT);  
  216.  server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //本地地址  
  217.  memset(&(server_addr.sin_zero), '\0', 8);  
  218.  if (bind(tempSockId, (struct sockaddr *)&server_addr,  
  219.   sizeof(server_addr)) == -1) {       //绑定服务 如果出错 则返回-1  
  220.   printf("bind error!\n");  
  221.   return -1;  
  222.  }  
  223.  if (listen(tempSockId, BACKLOG) == -1 ) {     //开始监听  
  224.   printf("listen error!\n");  
  225.   return -1;  
  226.  }  
  227.  return tempSockId;           //返回取得的SOCKET  
  228. }  
  229. /*********************** 
  230.  主函数main() 
  231.  程序入口 
  232. ***********************/  
  233. void main(int argc, char * argv[]) {  
  234.  /* 
  235.   * 调用WSAStartup() 便于访问sockets library 
  236.   */  
  237.  WSADATA wsaData;  
  238.  if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {  
  239.   fprintf(stderr, "WSAStartup failed.\n");  
  240.   exit(1);  
  241.  }  
  242.  printf("My web server started...\n");  
  243.  int server_socket;        //服务器的socket  
  244.  int acc_socket;         //接收到的用户连接的socket  
  245.  int sock_size = sizeof(struct sockaddr_in);    
  246.  struct sockaddr_in user_socket;     //客户连接信息  
  247.  server_socket = make_server_socket();   //创建服务器端的socket  
  248.  if (server_socket == -1) {      //创建socket出错  
  249.   printf("Server exception!\n");  
  250.   exit(2);  
  251.  }  
  252.  /* 
  253.   * 主循环 
  254.   */  
  255.  while(true) {  
  256.   acc_socket = accept(server_socket, (struct sockaddr *)&user_socket, &sock_size); //接收连接  
  257.     
  258.   //cout << inet_ntoa(user_socket.sin_addr) << endl;    //测试用:-)//  
  259.     
  260.   /* 
  261.    * 读取客户请求 
  262.    */  
  263.   int numbytes;  
  264.   char buf[100];  
  265.   if ((numbytes=recv(acc_socket, buf, 99, 0)) == -1) {  
  266.    perror("recv");  
  267.    exit(1);  
  268.   }  
  269.     
  270.   //printf("buf ... %s", buf);      //测试用  
  271.   /* 
  272.    * 处理用户请求 
  273.    */  
  274.   handle_req(buf, acc_socket);  
  275.  }  
  276. }  
  277. /**************程序结束Server.cpp******************/ 
阅读(2575) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~