c web service_简单并快乐着的博客-程序员资料_c ++ web service

技术标签: webserver  


转自 http://blog.163.com/wzbwzb_187/blog/static/6632425720106424158919/

以下是源代码:

 
/**************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******************/
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lqxandroid2012/article/details/51036587

智能推荐

Windows Server 2008 R2 AD域服务器安装与配置_小喇叭biubiubiu的博客-程序员资料

前言由于本人第一次搭建AD域服务器,所以本文参考到其他的博客;发表这篇博客主要为了记录一下自己操作过程以及分享经验。注意一、安装AD前最好不要安装DNS服务二、安装完成后一定要运行dcpomo.exe程序三、安装前请确认是否在网络属性中制定了内网(域中)的DNS服务器1.打开服务管理器2.在左侧点击角色,在右侧点击添加角色3.弹出添加角色向导,点击下一步4.勾选Active...

vmware配置虚拟机centos6.9/centos7_amunamuna的博客-程序员资料_centos6.9 7

mac本安装vmware虚拟机vmware创建虚拟机:实现虚拟机和本地网络互通,安装vmware之后会在本地生成一块vmnet8。本地通过ifconfig查看vmnet8对应的ip地址,然后更改相应的虚拟机IP。更改mac地址:vim /etc/udev/rules.d/70-persistent-net.rules更改网络配置:vim /etc/sysconfig/network-...

r420 raid linux,戴尔服务器启动和raid设置(以dell r420为例)_BLACK枪骑兵的博客-程序员资料

戴尔服务器启动过程:memory initialize --&gt; iDRAC --&gt; sas ahci controller --&gt; NIC controller --&gt; raid controller--&gt; firmware initialize -&gt; lifecycle controller --&gt; Select boot device --&gt;...

【网站搭建】修改namesilo自带的域名服务器至cloudflare_DanteIoVeYou的博客-程序员资料_cloudflare namesilo

问题描述Namesilo是一个不错的购买域名的网站,但是用namesilo自带的域名管理系统操作实在太垃,于是,我们从namesilo处注册的域名用cloudflare提供的域名服务器进行解析。解决方案登录cloudflare:https://www.cloudflare.com/注册couldflare账号添加要托管的域名选择免费套餐接下来修改域名服务器进入namesilo域名管理界面复制粘贴等待一会儿查一下ns记录是否修改到了cloudflar

jsp&Servlet-单表信息操作_fightingcoder419的博客-程序员资料

1.建立数据库中的book表2.将book表中的属性封装在model文件夹下package com.oracle.book.model;import java.io.Serializable;import java.util.Date;@SuppressWarnings("serial")public class Book implements Serializable{

Solved: Atlassian login windows keep popping up_u010950918的博客-程序员资料

When using Sourcetree to connect with Bitbucket, the atlassian is always asking for credentials.Solution:update git and set in the Sourcetree: use system git by default

随便推点

C++ 报错:no operator defined which takes a right-hand operand of type 'class std::bas_秋天的从从的博客-程序员资料_right-hand operand

C++ 报错:no operator defined which takes a right-hand operand of type 'class std::bas1 错误提示2 错误原因3 错误代码4 解决办法参考:https://blog.csdn.net/wen_yang/article/details/726313801 错误提示binary ‘&lt;&lt;’ : no ope...

wince6.0 开发流程_butterfly的博客-程序员资料

wince6.0 开发流程Windows CE概述 从6.0版本开始,Windows CE的名字改为Windows Embedded CE,当然这也是为了结合Windows Embedded品牌作出的改变。CE经过了十年的风风雨雨之后,终于在CE 6.0这个版本上再次浴火重生了。CE 6.0经历了CE历史上第二次内核重写,使CE操作系统更加符合当今嵌入式开发的方向。     CE 6.0在

obs多推流地址_给大家推荐一款电脑推流多开、电脑推流十开软件、多平台推流软件..._weixin_39571087的博客-程序员资料

常用的推流软件有Open Broadcaster Software、Adobe Flash Media Encoder、iAVcast、此刻直播助手等。估计使用最多的应该就是第一个OBS推流软件。OBS是开源免费的推流软件,功能强大,但是实现推流多开有局限性。目前市面上,稳定的多平台推流软件和多开推流软件几乎没有,这里我给大家推荐一个可以多开推流的电脑十开推流软件。启航自媒体-十开群控直播电脑推流...

webflux怎么加载html,Webflux快速入门 - 聂晨 - 博客园_激光不是红外线的博客-程序员资料

SpringWebflux是SpringFramework5.0添加的新功能,WebFlux本身追随当下最火的Reactive Programming而诞生的框架,那么本篇就来简述一下这个框架到底是做什么的一、关于WebFlux我们知道传统的Web框架,比如说:struts2,springmvc等都是基于Servlet API与Servlet容器基础之上运行的,在Servlet3.1之后才有了异步...

iOS-动态图保存_疯兔子Uknow的博客-程序员资料

前言:今日,需求要求保存一个gif动态图.原理比较简单.但是中间触发了一些问题.和概念在这里给大家分享一下动态图GIF.WEBP.APNG 三者区别我这里暂不讨论.不是专业的所以深究下去会有很多东西需要吸收iOS动态图保存iOS相册支持GIF 和APNG 的保存 目测iOS11.0在相册中也可以播放GIF 的动态图.而iOS8.3不能. writeImageDataToSavedPhotosAlb

react 一般组件实现跳转withRouter_下一个路口yj的博客-程序员资料_withrouer

withRouter可以加工一般组件,让一般组件具备路由组件所特有的ApiwithRouer的返回值一个新组件