C语言实现的Web服务器
生活随笔
收集整理的這篇文章主要介紹了
C语言实现的Web服务器
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
另一篇:
以下是源代碼:
/**************filename: Server.cpp****************
? 該程序通過(guò)標(biāo)準(zhǔn)socket實(shí)現(xiàn)簡(jiǎn)單Http服務(wù)器
? 運(yùn)行該服務(wù)器可以通過(guò)瀏覽器訪問(wèn)服務(wù)器目錄下的
? Html文件和jpg圖片 完成初步的Http服務(wù)器功能
***************************************************/ #include <winsock.h>
#include <sys/stat.h>
#include <iostream>
using namespace std; #define SERVER_PORT 10000? ? ? ? ? ? ? ? ? //自定義的服務(wù)端口
#define HOSTLEN 256? ? ? ? ? ? ? ? ? ? ? //主機(jī)名長(zhǎng)度
#define BACKLOG 10? ? ? ? ? ? ? ? ? ? ? //同時(shí)等待的連接個(gè)數(shù)
/**************************************
? 該方法包裝了send()
? 通過(guò)該方法發(fā)送數(shù)據(jù) 能夠全部發(fā)出
? 沒(méi)有遺漏
**************************************/
int sendall(int s, char *buf, int *len) {
? int total = 0;? ? ? ? ? ? ? ? ? ? ? // 已經(jīng)發(fā)送字節(jié)數(shù)
? int bytesleft = *len;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //還剩余多少字節(jié)
? int n;
? while(total < *len) {
? ? n = send(s, buf+total, bytesleft, 0);
? ? if (n == -1) { break; }
? ? total += n;
? ? bytesleft -= n;
? }
? *len = total;? ? ? ? ? ? ? ? ? ? ? // 返回實(shí)際發(fā)送出去的字節(jié)數(shù)
? return n==-1?-1:0;? ? ? ? ? ? ? ? ? ? // 成功發(fā)送返回0 失敗-1
} /**************************************
? 該方法處理錯(cuò)誤請(qǐng)求
? 并向客戶端發(fā)送錯(cuò)誤信息
**************************************/
void wrong_req(int sock) {
? char* error_head = "HTTP/1.0 501 Not Implemented\r\n";? //輸出501錯(cuò)誤
? int len = strlen(error_head);
? if (sendall(sock, error_head, &len) == -1) {? ? ? //向客戶發(fā)送
? ? 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;
? }
} /**********************************
? 該方法判斷用戶請(qǐng)求的文件是否存在
? 不存在返回true 存在返回false
***********************************/
bool not_exit(char* arguments) {
? struct stat dir_info;
? return (stat(arguments, &dir_info) == -1);
} /*************************************
? 所請(qǐng)求的文件不存在
*************************************/
void file_not_found(char* arguments, int sock) { char* error_head = "HTTP/1.0 404 Not Found\r\n";? ? ? //構(gòu)造404錯(cuò)誤head
? int len = strlen(error_head);
? if (sendall(sock, error_head, &len) == -1) {? ? ? ? //向客戶端發(fā)送
? ? 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;
? }? ? ? ?
} /*************************************
? 發(fā)送Http協(xié)議頭部信息
? 其中包括響應(yīng)類型和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) {? ? ? //向連接的客戶端發(fā)送數(shù)據(jù)
? ? printf("Sending error");
? ? return;
? }
if (content_type) {? ? ? ? ? ? ? ? ? //content_type不為空
? ? char temp_1[30] = "Content-type: ";? ? ? ? //準(zhǔn)備好要連接的字串
? ? strcat(temp_1, content_type);? ? ? ? ? //構(gòu)造content_type
? ? strcat(temp_1, "\r\n");
? ? len = strlen(temp_1);
? ? if (sendall(send_to, temp_1, &len) == -1) {
? ? ? printf("Sending error!");
? ? ? return;
? ? }
? }
} /***********************************
? 取得用戶所請(qǐng)求的文件類型
? 即文件后綴 (.html .jpg .gif)
************************************/
char* file_type(char* arg) {
? char * temp;? ? ? ? ? ? ? ? ? ? //臨時(shí)字符串指針
? if ((temp=strrchr(arg,'.')) != NULL) {? ? ? ? //取得后綴
? ? return temp+1;
? }
? return "";? ? ? ? ? ? ? ? ? ? ? //如果請(qǐng)求的文件名中沒(méi)有. 則返回空串
} /*************************************
? 該方法為程序核心
? 負(fù)責(zé)真正發(fā)送文件 如*.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;? ? ? ? ? ? ? ? ? //每次讀得的字節(jié)數(shù)
?
? if (strcmp(extension, "html") == 0) {? ? ? ? //發(fā)送內(nèi)容為html
? ? content_type = "text/html";
? }
if (strcmp(extension, "gif") == 0) {? ? ? ? //發(fā)送內(nèi)容為gif
? ? content_type = "image/gif";
? }
if (strcmp(extension, "jpg") == 0) {? ? ? ? //發(fā)送內(nèi)容為jpg
? ? content_type = "image/jpg";
? }
read_from = fopen(arguments, "r");? ? ? ? ? //打開用戶指定的文件準(zhǔn)備讀取
? if(read_from != NULL) {? ? ? ? ? ? ? ? //指針不為空
? ? char read_buf[128];? ? ? ? ? ? ? ? //讀文件時(shí)的字節(jié)緩存數(shù)組
? ? send_header(sock, content_type);? ? ? ? //發(fā)送協(xié)議頭
? ? send(sock, "\r\n", 2, 0);? ? ? ? ? ? //再加一個(gè)"\r\n" 不能缺少 格式要求
? while(!feof(read_from)) {? ? ? ? ? ? //判斷文件是否已經(jīng)結(jié)束
? ? ? fgets(read_buf, 128, read_from);? ? ? //讀取
? ? ? int len = strlen(read_buf);
? ? ? if (sendall(sock, read_buf, &len) == -1) {? //發(fā)送數(shù)據(jù)
? ? ? ? printf("Sending error!");? ? ? ? //出現(xiàn)發(fā)送錯(cuò)誤顯示到控制臺(tái) 繼續(xù)發(fā)送
? ? ? ? continue;
? ? ? }
? ? }
? }
} /***********************************
? 解析并處理用戶請(qǐng)求
***********************************/
void handle_req(char* request, int client_sock) { char command[BUFSIZ];? ? ? ? ? ? ? ? //保存解析到的命令字段 GET PUT
? char arguments[BUFSIZ];? ? ? ? ? ? ? ? //保存解析到的請(qǐng)求的文件
/*
? * 在用戶請(qǐng)求前加上當(dāng)前目錄符號(hào)
? */
? strcpy(arguments, "./");? ? ? ? ? ? ? //注意該符號(hào)在不同操作系統(tǒng)的區(qū)別
/*
? * 解析請(qǐng)求
? */
? if (sscanf(request, "%s%s", command, arguments+2) != 2) {
? ? return;? ? ? ? ? ? ? ? ? ? ? //解析出錯(cuò)在返回
? }
?
? printf("handle_cmd:? ? ? %s\n",command);? ? ? ? //向控制臺(tái)輸出此時(shí)的命令
? printf("handle_path:? ? %s\n",arguments);? ? ? //向控制臺(tái)輸出此時(shí)的請(qǐng)求路徑
?
? if (strcmp(command, "GET") != 0) {? ? ? ? ? //請(qǐng)求命令格式是否正確
? ? wrong_req(client_sock);
? ? return;
? }
if (not_exit(arguments)) {? ? ? ? ? ? ? //請(qǐng)求的文件是否存在? ?
? ? file_not_found(arguments, client_sock);
? ? return;
? }
send_file(arguments, client_sock);? ? ? ? ? //命令格式及請(qǐng)求路徑正確則發(fā)送數(shù)據(jù)
?
? return;
} /*************************************
? 該方法構(gòu)造服務(wù)器端的SOCKET
? 返回構(gòu)造好的socket描述符
*************************************/
int make_server_socket() {
? struct sockaddr_in server_addr;? ? ? ? ? ? ? //服務(wù)器地址結(jié)構(gòu)體
int tempSockId;? ? ? ? ? ? ? ? ? ? ? //臨時(shí)存儲(chǔ)socket描述符
tempSockId = socket(PF_INET, SOCK_STREAM, 0);
?
? if (tempSockId == -1) {? ? ? ? ? ? ? ? ? //如果返回值為-1 則出錯(cuò)
? ? return -1;
? }
/*
? * 填充服務(wù)器連接信息
? */
? 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) {? ? ? ? ? ? ? //綁定服務(wù)如果出錯(cuò) 則返回-1
? ? printf("bind error!\n");
? ? return -1;
? }
if (listen(tempSockId, BACKLOG) == -1 ) {? ? ? ? ? //開始監(jiān)聽
? ? printf("listen error!\n");
? ? return -1;
? }
return tempSockId;? ? ? ? ? ? ? ? ? ? ? //返回取得的SOCKET
} /***********************
? 主函數(shù)main()
? 程序入口
***********************/
void main(int argc, char * argv[]) { /*
? * 調(diào)用WSAStartup() 便于訪問(wèn)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;? ? ? ? ? ? ? ? //服務(wù)器的socket
? int acc_socket;? ? ? ? ? ? ? ? ? //接收到的用戶連接的socket
? int sock_size = sizeof(struct sockaddr_in);? ?
struct sockaddr_in user_socket;? ? ? ? ? //客戶連接信息
server_socket = make_server_socket();? ? ? //創(chuàng)建服務(wù)器端的socket
if (server_socket == -1) {? ? ? ? ? ? //創(chuàng)建socket出錯(cuò)
? ? printf("Server exception!\n");
? ? exit(2);
? }
/*
? *? 主循環(huán)
? */
? while(true) {
? ? acc_socket = accept(server_socket, (struct sockaddr *)&user_socket, &sock_size);? //接收連接
? ?
? ? //cout << inet_ntoa(user_socket.sin_addr) << endl;? ? ? //測(cè)試用:-)//
? ?
? ? /*
? ? *? 讀取客戶請(qǐng)求
? ? */
? ? int numbytes;
? ? char buf[100];
? ? if ((numbytes=recv(acc_socket, buf, 99, 0)) == -1) {
? ? ? perror("recv");
? ? ? exit(1);
? ? }
?
? ? //printf("buf ... %s", buf);? ? ? ? ? ? //測(cè)試用
? /*
? ? * 處理用戶請(qǐng)求
? ? */
? ? handle_req(buf, acc_socket);
? }
} /**************程序結(jié)束Server.cpp******************/
標(biāo)準(zhǔn)C實(shí)現(xiàn)WEB服務(wù)器
http://blog.sina.com.cn/s/blog_4b73e7600100b02c.html 本文原文地址: http://blog.sina.com.cn/s/blog_4b73e760010007id.html 自己研究了好幾天終于寫出來(lái)一個(gè),哈哈,當(dāng)然也從網(wǎng)上得到了很多的幫助拉。謝謝大家咯!這個(gè)版本還不是很完善,但Web服務(wù)器的基本框架已經(jīng)出來(lái)了,還有部分的功能需要進(jìn)行進(jìn)一步的測(cè)試和修改。雖然說(shuō)C的開發(fā)比較慢,對(duì)于程序員來(lái)說(shuō)比較難以操作,但通過(guò)用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) {
?
?
?
?
?
?
?
?
?
?
?
} /**************************************
?
?
**************************************/
void wrong_req(int sock) {
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
} /**********************************
?
?
***********************************/
bool not_exit(char* arguments) {
?
?
} /*************************************
?
*************************************/
void file_not_found(char* arguments, int sock) {
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
} /*************************************
?
?
*************************************/
void send_header(int send_to, char* content_type) {
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
} /***********************************
?
?
************************************/
char* file_type(char* arg) {
?
?
?
?
?
} /*************************************
?
?
*************************************/
void send_file(char* arguments, int sock) {
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
} /***********************************
?
***********************************/
void handle_req(char* request, int client_sock) {
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
} /*************************************
?
?
*************************************/
int make_server_socket() {
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
} /***********************
?
?
***********************/
void main(int argc, char * argv[]) {
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
} /**************程序結(jié)束Server.cpp******************/
總結(jié)
以上是生活随笔為你收集整理的C语言实现的Web服务器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 豆浆机多少钱啊?
- 下一篇: 使用VS2010调试技巧让C指针无处遁形