自己研究了好几天终于写出来一个,哈哈,当然也从网上得到了很多的帮助拉。谢谢大家咯!这个版本还不是很完善,但Web服务器的基本框架已经出来了,还有部分的功能需要进行进一步的测试和修改。虽然说C的开发比较慢,对于程序员来说比较难以操作,但通过用C写这些很底层的东西,可以更好的了解的象java的socket中的工作原理。有一定的帮助!
 
以下是源代码:
 
/**************filename: Server.cpp****************
 该程序通过标准socket实现简单Http服务器
 运行该服务器可以通过浏览器访问服务器目录下的
 Html文件和jpg图片 完成初步的Http服务器功能
***************************************************/
#include <winsock.h>
#include <sys/stat.h>
#include <iostream>
using namespace std;
#define SERVER_PORT 10000         //自定义的服务端口
#define HOSTLEN 256           //主机名长度
#define BACKLOG 10           //同时等待的连接个数
/**************************************
 该方法包装了send()
 通过该方法发送数据 能够全部发出
 没有遗漏
**************************************/
int sendall(int s, char *buf, int *len) {
 int total = 0;           // 已经发送字节数
 int bytesleft = *len;                                   //还剩余多少字节
 int n;
 while(total < *len) {
  n = send(s, buf+total, bytesleft, 0);
  if (n == -1) { break; }
  total += n;
  bytesleft -= n;
 }
 *len = total;           // 返回实际发送出去的字节数
 return n==-1?-1:0;          // 成功发送返回0 失败-1
}
/**************************************
 该方法处理错误请求
 并向客户端发送错误信息
**************************************/
void wrong_req(int sock) {
 char* error_head = "HTTP/1.0 501 Not Implemented\r\n"; //输出501错误
 int len = strlen(error_head);
 if (sendall(sock, error_head, &len) == -1) {   //向客户发送
  printf("Sending failed!");
  return;
 }      
 char* error_type = "Content-type: text/plain\r\n";  
 len = strlen(error_type);
 if (sendall(sock, error_type, &len) == -1) {
  printf("Sending failed!");
  return;
 }
 char* error_end = "\r\n";
 len = strlen(error_end);
 if (sendall(sock, error_end, &len) == -1) {
  printf("Sending failed!");
  return;
 }
 char* prompt_info = "The command is not yet completed\r\n";
 len = strlen(prompt_info);
 if (sendall(sock, prompt_info, &len) == -1) {
  printf("Sending failed!");
  return;
 }
}
/**********************************
 该方法判断用户请求的文件是否存在
 不存在返回true 存在返回false
***********************************/
bool not_exit(char* arguments) {
 struct stat dir_info;
 return (stat(arguments, &dir_info) == -1);
}
/*************************************
 所请求的文件不存在
*************************************/
void file_not_found(char* arguments, int sock) {
 char* error_head = "HTTP/1.0 404 Not Found\r\n";   //构造404错误head
 int len = strlen(error_head);
 if (sendall(sock, error_head, &len) == -1) {    //向客户端发送
  printf("Sending error!");
  return;
 }   
 char* error_type = "Content-type: text/plain\r\n";
 len = strlen(error_type);
 if (sendall(sock, error_type, &len) == -1) {
  printf("Sending error!");
  return;
 }
 char* error_end = "\r\n";
 len = strlen(error_end);
 if (sendall(sock, error_end, &len) == -1) {
  printf("Sending error!");
  return;
 }
 char prompt_info[50] = "Not found:  ";
 strcat(prompt_info, arguments);
 len = strlen(prompt_info);
 if (sendall(sock, prompt_info, &len) == -1) {    //输出未找到的文件
  printf("Sending error!");
  return;
 }    
}
/*************************************
 发送Http协议头部信息
 其中包括响应类型和Content Type
*************************************/
void send_header(int send_to, char* content_type) {
 
 char* head = "HTTP/1.0 200 OK\r\n";     //正确的头部信息
 int len = strlen(head);
 if (sendall(send_to, head, &len) == -1) {   //向连接的客户端发送数据
  printf("Sending error");
  return;
 }
 if (content_type) {         //content_type不为空
  char temp_1[30] = "Content-type: ";    //准备好要连接的字串
  strcat(temp_1, content_type);     //构造content_type
  strcat(temp_1, "\r\n");
  len = strlen(temp_1);
  if (sendall(send_to, temp_1, &len) == -1) {
   printf("Sending error!");
   return;
  }
 }
}
/***********************************
 取得用户所请求的文件类型
 即文件后缀 (.html .jpg .gif)
************************************/
char* file_type(char* arg) {
 char * temp;          //临时字符串指针
 if ((temp=strrchr(arg,'.')) != NULL) {    //取得后缀
  return temp+1;
 }
 return "";           //如果请求的文件名中没有. 则返回空串
}
/*************************************
 该方法为程序核心
 负责真正发送文件 如*.html *.jpg等
*************************************/
void send_file(char* arguments, int sock) {
 char* extension = file_type(arguments);    //获得文件后缀名
 char* content_type = "text/plain";     //初始化type='text/plain'
 FILE* read_from;         //本地文件指针 从该文件中读取.html .jpg等
 int readed = -1;         //每次读得的字节数
 
 if (strcmp(extension, "html") == 0) {    //发送内容为html
  content_type = "text/html";
 }
 if (strcmp(extension, "gif") == 0) {    //发送内容为gif
  content_type = "image/gif";
 }
 if (strcmp(extension, "jpg") == 0) {    //发送内容为jpg
  content_type = "image/jpg";
 }
 read_from = fopen(arguments, "r");     //打开用户指定的文件 准备读取
 if(read_from != NULL) {        //指针不为空
  char read_buf[128];        //读文件时的字节缓存数组
  send_header(sock, content_type);    //发送协议头
  send(sock, "\r\n", 2, 0);      //再加一个"\r\n" 不能缺少 格式要求
  while(!feof(read_from)) {      //判断文件是否已经结束
   fgets(read_buf, 128, read_from);   //读取
   int len = strlen(read_buf);
   if (sendall(sock, read_buf, &len) == -1) { //发送数据
    printf("Sending error!");    //出现发送错误 显示到控制台 继续发送
    continue;
   }
  }
 }
}
/***********************************
 解析并处理用户请求
***********************************/
void handle_req(char* request, int client_sock) {
 char command[BUFSIZ];        //保存解析到的命令字段 GET PUT
 char arguments[BUFSIZ];        //保存解析到的请求的文件
 /*
  * 在用户请求前加上当前目录符号
  */
 strcpy(arguments, "./");       //注意该符号在不同操作系统的区别
 /*
  * 解析请求
  */
 if (sscanf(request, "%s%s", command, arguments+2) != 2) {
  return;           //解析出错在返回
 }
 
 printf("handle_cmd:    %s\n",command);    //向控制台输出此时的命令
 printf("handle_path:   %s\n",arguments);   //向控制台输出此时的请求路径
 
 if (strcmp(command, "GET") != 0) {     //请求命令格式是否正确
  wrong_req(client_sock);
  return;
 }
 if (not_exit(arguments)) {       //请求的文件是否存在  
  file_not_found(arguments, client_sock);
  return;
 }
 send_file(arguments, client_sock);     //命令格式及请求路径正确则发送数据
 
 return;
}
/*************************************
 该方法构造服务器端的SOCKET
 返回构造好的socket描述符
*************************************/
int make_server_socket() {
 struct sockaddr_in server_addr;       //服务器地址结构体
 int tempSockId;           //临时存储socket描述符
 tempSockId = socket(PF_INET, SOCK_STREAM, 0);
 
 if (tempSockId == -1) {         //如果返回值为-1 则出错
  return -1;
 }
 /*
  * 填充服务器连接信息
  */
 server_addr.sin_family = AF_INET;
 server_addr.sin_port = htons(SERVER_PORT);
 server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //本地地址
 memset(&(server_addr.sin_zero), '\0', 8);
 if (bind(tempSockId, (struct sockaddr *)&server_addr,
  sizeof(server_addr)) == -1) {       //绑定服务 如果出错 则返回-1
  printf("bind error!\n");
  return -1;
 }
 if (listen(tempSockId, BACKLOG) == -1 ) {     //开始监听
  printf("listen error!\n");
  return -1;
 }
 return tempSockId;           //返回取得的SOCKET
}
/***********************
 主函数main()
 程序入口
***********************/
void main(int argc, char * argv[]) {
 /*
  * 调用WSAStartup() 便于访问sockets library
  */
 WSADATA wsaData;
 if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
  fprintf(stderr, "WSAStartup failed.\n");
  exit(1);
 }
 printf("My web server started...\n");
 int server_socket;        //服务器的socket
 int acc_socket;         //接收到的用户连接的socket
 int sock_size = sizeof(struct sockaddr_in);  
 struct sockaddr_in user_socket;     //客户连接信息
 server_socket = make_server_socket();   //创建服务器端的socket
 if (server_socket == -1) {      //创建socket出错
  printf("Server exception!\n");
  exit(2);
 }
 /*
  * 主循环
  */
 while(true) {
  acc_socket = accept(server_socket, (struct sockaddr *)&user_socket, &sock_size); //接收连接
  
  //cout << inet_ntoa(user_socket.sin_addr) << endl;    //测试用:-)//
  
  /*
   * 读取客户请求
   */
  int numbytes;
  char buf[100];
  if ((numbytes=recv(acc_socket, buf, 99, 0)) == -1) {
   perror("recv");
   exit(1);
  }
  
  //printf("buf ... %s", buf);      //测试用
  /*
   * 处理用户请求
   */
  handle_req(buf, acc_socket);
 }
}
/**************程序结束Server.cpp******************/

C语言实现的Web服务器(转-kungstriving)的更多相关文章

  1. C语言构建小型Web服务器

    #include <stdio.h> #include <sys/socket.h> #include <stdlib.h> #include <string ...

  2. 第37章 socket编程 之练习:实现简单的web服务器

    一.参考网址 1.linux C学习之实现简单的web服务器 2.C语言实现简单Web服务器(一)

  3. Web服务器和动态语言如何交互--CGI&FastCGI&FPM浅谈

    一个用户的Request是如何经过Web服务器(Apache,Nginx,IIS,Light)与后端的动态语言(如PHP等)进行交互并将结果返回给用户的呢? 本文浅谈个人观点,可能有误,欢迎拍砖,共同 ...

  4. 基于windows IIS的C语言CGI WEB服务器环境搭建

    网页编程对我来说特别亲切,因为我就是从html.ASP.PHP一步步接触编程的.自己的编程爱好也是从那里一点一点被满足.不过离开大学之后很久没有碰过WEB了,最近看到嵌入式中的涉及到的web服务器,了 ...

  5. web服务器和后端语言的关系

    1.web服务nginx和php的相互关系  : https://www.cnblogs.com/luckylihuizhou/p/6387171.html 个人理解:web服务器本身没有处理后端语言 ...

  6. C/C++编程日记:用C语言实现的简单Web服务器(Linux),全代码分享!

    相信大家对Apache都有所听闻,Apache是目前使用最为广泛我Web服务器.大家可以从news.netcraft.com/这个网站得到证实. 这是腾讯的uptime.netcraft.com/up ...

  7. 闲来无聊,研究一下Web服务器 的源程序

    web服务器是如何工作的 1989年的夏天,蒂姆.博纳斯-李开发了世界上第一个web服务器和web客户机.这个浏览器程序是一个简单的电话号码查询软件.最初的web服务器程序就是一个利用浏览器和web服 ...

  8. Raspkate - 基于.NET的可运行于树莓派的轻量型Web服务器

    最近在业余时间玩玩树莓派,刚开始的时候在树莓派里写一些基于wiringPi库的C语言程序来控制树莓派的GPIO引脚,从而控制LED发光二极管的闪烁,后来觉得,是不是可以使用HTML5+jQuery等流 ...

  9. 一个简单的 Web 服务器 [未完成]

    最近学习C++,linux和网络编程,想做个小(mini)项目.  就去搜索引擎, 开源中国, Sourceforge上找http server的项目. 好吧,也去了知乎.    知乎上程序员氛围好, ...

随机推荐

  1. vs2010打包(带数据库)图文详解

    最近刚刚打包发布了用VS2010开发的一个收费系统,借此讲一讲打包过程,供大家参考. 首先打开已经完成的工程,如图: 下面开始制作安装程序包. 第一步:[文件]——[新建]——[项目]——安装项目. ...

  2. lr各种问题以及解决办法

    LR 脚本为空的解决方法: 1.去掉ie设置中的第三方支持取消掉 2.在系统属性-高级-性能-数据执行保护中,添加loadrunner安装目录中的vugen.exe文件 遇到flight界面为空的解决 ...

  3. jquery iframe自适应高度[转]

      经典代码 iFrame 自适应高度,在IE6/IE7/IE8/Firefox/Opera/Chrome/Safari通过测试. 很古老的方法: <iframe src="../In ...

  4. php WIN下编译注意问题

    下载VC2012,安装打开CMD 须运行 vcvars32.bat (初始化VC编译环境) 下载PHP WIN编译包:http://windows.php.net/downloads/php-sdk/ ...

  5. [转]c++类的构造函数详解

    c++构造函数的知识在各种c++教材上已有介绍,不过初学者往往不太注意观察和总结其中各种构造函数的特点和用法,故在此我根据自己的c++编程经验总结了一下c++中各种构造函数的特点,并附上例子,希望对初 ...

  6. Oracle 字符串分割排序冒泡算法

    例子: 一个字符串"11,15,13,17,12",以逗号分割,现在要排序成"11,12,13,15,17". 写了一个实现方法,记录下来以备后用: ----- ...

  7. Reflector反编译WinForm程序重建项目资源和本地资源

    工具:vs2012..NET Reflector8.1.0.35 要解决的问题: 通过Reflector反编译生成的代码可以编译通过并显示窗体的本地资源和项目资源图片 一.测试项目 两个图片分别放在项 ...

  8. 微信、QQ浏览器X5内核问题汇总

    一. 资料汇总 1.前端H5调起QQ浏览器的总结:http://km.oa.com/group/22486/articles/show/210189?kmref=search 2.Android We ...

  9. 转:Ajax中的get和post两种请求方式的异同

    1. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到.post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML ...

  10. Top Five Hacker Tools Every CISO Should Understand

    As the role of the CISO continues to evolve within organizations towards that of an executive level ...