自己研究了好几天终于写出来一个,哈哈,当然也从网上得到了很多的帮助拉。谢谢大家咯!这个版本还不是很完善,但Web服务器的基本框架已经出来了,还有部分的功能需要进行进一步的测试和修改。虽然说C的开发比较慢,对于程序员来说比较难以操作,但通过用C写这些很底层的东西,可以更好的了解的象java的socket中的工作原理。有一定的帮助!
以下是源代码:
#include <winsock.h>
#include <sys/stat.h>
#include <iostream>
using namespace std;
#define SERVER_PORT 10000 //自定义的服务端口
#define HOSTLEN 256 //主机名长度
#define BACKLOG 10 //同时等待的连接个数
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;
}
}
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;
}
}
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;
}
}
}
char* file_type(char* arg) {
char * temp; //临时字符串指针
if ((temp=strrchr(arg,'.')) != NULL) { //取得后缀
return temp+1;
}
return ""; //如果请求的文件名中没有. 则返回空串
}
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;
}
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
}
void main(int argc, char * argv[]) {
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);
}
}
分享到:
相关推荐
Linux下基于C++的轻量级Web服务器; (1)使用 线程池 + 非阻塞socket + epoll(ET和LT均实现) + 事件处理(Reactor、Proactor) 的并发模型; (2)使用状态机解析HTTP请求报文,支持解析GET和POST请求; (3)访问...
在本文档中,作者分享了如何使用C++在Windows环境下构建一个简单的Web服务器。这个Web服务器的实现基于C语言的套接字编程,这有助于开发者更深入地理解网络通信的基础和Java中的Socket工作原理。 首先,我们需要...
测试方式(依次在浏览器输入一下内容进行不同情形的测试): 127.0.0.1:9988 ...2、CGI实现不够科学,可以尝试使用FASTCGI 3、不支持https 4、不支持回应chunked数据 感兴趣的同学可以继续完善相关功能.
在C++领域,开发Web服务框架,特别是HTTP Web框架,是一项技术性强且具有挑战性的任务。本主题将探讨如何利用Microsoft的Visual Studio 2015集成开发环境(IDE)以及Boost库来设计和实现这样的框架。Boost库是C++...
5. **多平台兼容**:本实现支持Windows和Linux操作系统,这意味着代码可能使用了跨平台的库,如libevent或libuv,来处理异步I/O和线程。 6. **安全性**:WebSocket可以通过TLS/SSL(即HTTPS的WebSocket版本,称为...
本文将深入探讨一个基于C++实现的Web服务器,并着重讲解其核心概念和技术细节。 首先,我们要了解C++语言在构建Web服务器中的作用。C++是一种强大的系统级编程语言,因其高效、灵活和对底层硬件的直接控制能力,常...
在本文中,我们将深入探讨如何使用Microsoft Foundation Class (MFC) 库在Visual C++ 6.0环境下实现一个简单的Web服务器程序。MFC是微软为C++开发人员提供的一套面向对象的类库,它封装了Windows API,使得Windows...
在本文中,我们将深入探讨WebSocketPP库的特性、如何在Windows平台上利用重叠I/O(Overlapped I/O)以及如何构建基于此库的Web服务器。 WebSocketPP库的设计目标是简单易用且高度可定制。它支持多种事件驱动模型,...
【简易WEB服务器(C++)】是一个编程项目,旨在通过C++语言实现一个基础的互联网服务器,能够响应用户的HTTP请求并提供文件服务。这个项目主要关注网络编程和HTTP协议的理解,是学习网络通信和服务器开发的初级实践...
总的来说,这个C++实现的Web服务器是一个基础的教学示例,它可以帮助初学者理解Web服务器的基本工作流程,包括接收连接、处理请求和发送响应。尽管功能有限,但它是进一步学习网络编程和Web服务器开发的良好起点。
总之,C++在Windows平台下通过WinINet库可以方便地实现与Web服务器的通信,无论是进行简单的GET请求获取资源,还是复杂的POST请求提交数据,都可通过精心设计的C++接口轻松实现。这为开发跨平台、高性能的网络应用...
【标题】中的“基于C++开发的WEB服务器”是指使用C++编程语言设计和实现的Web服务器软件。这种服务器能够处理HTTP协议,为用户提供Web服务。C++是一种强大的、面向对象的编程语言,适合开发高性能的系统级软件,如...
在使用WebSocketPP构建Web服务器时,首先需要设置服务器的基本配置,如监听端口、处理连接的回调函数等。然后,服务器会进入事件循环,等待客户端的连接请求。一旦有新的WebSocket连接建立,服务器可以接收和发送...
标题“实用的C++写Web的例子”暗示我们将探讨一个实际的示例,这个例子可能包括创建一个简单的Web服务器,该服务器能够处理HTTP请求并返回响应。在Windows环境下,这通常涉及使用Microsoft的开发工具,如Visual ...
在C++中,进行HTTP文件上传到Web服务器时,可能会遇到中文参数乱码的问题。这是因为HTTP协议本身并不处理字符编码,而是依赖于上层的应用层协议(如HTTP头或者POST数据)来处理字符集。当涉及到非ASCII字符,如中文...
在本文中,我们将深入探讨如何使用C++实现一个服务器POST访问功能,并且解析接收到的JSON数据流。C++作为一种强大的编程语言,广泛应用于系统级编程、游戏开发以及服务器端应用。结合HTTP协议和JSON数据格式,我们...
本项目是用C++实现的一个简单Web服务器,它能够处理GET请求,是学习多线程技术和网络编程的典型实例。 首先,让我们详细探讨“多线程”这一概念。在计算机程序设计中,多线程允许一个应用程序同时执行多个不同的...
在描述中提到的“vc开发”可能是指使用Visual C++,这是一个微软提供的IDE,集成了编译器、调试器以及项目管理工具,支持C++开发,并且可以方便地创建和管理Windows下的Web应用程序。Visual C++还提供了对MFC...
WEB服务器的设计与实现毕业论文 本文主要论述了 WEB 服务器的设计思想和实现方法,涵盖了 WEB 服务器的特点、关键技术和实现过程。以下是本文所涉及的知识点: 1. WEB 服务器的特点: WEB 服务器是基于 WEB 的应用...