| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1784 人关注过本帖, 1 人收藏
标题:一个简单的 HTTP 服务器
只看楼主 加入收藏
madfrogme
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:21
帖 子:1160
专家分:1106
注 册:2009-6-24
结帖率:98.63%
收藏(1)
 问题点数:0 回复次数:7 
一个简单的 HTTP 服务器
程序代码:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "hacking.h"
#include "hacking-network.h"

#define PORT 50000   // 用户连接端口 
#define WEBROOT "./webroot" //浏览器的默认目录 

void handle_connection(int, struct sockaddr_in *); //处理請求的函数 
int get_file_size(int); // 获得打开文件的大小 

int main(void) {
   int sockfd, new_sockfd, yes=1;
   struct sockaddr_in host_addr, client_addr;   // 
   socklen_t sin_size;

   printf("接受来自端口 %d 的請求\n", PORT);

   if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
      fatal("无法生成套接字");

   if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
      fatal("設定套接字为SO_REUSEADDR ");

   host_addr.sin_family = AF_INET;      
   host_addr.sin_port = htons(PORT);   
   host_addr.sin_addr.s_addr = INADDR_ANY; // 自动設定自身IP 
   memset(&(host_addr.sin_zero), '\0', 8); // 结构体的最后8字节清0
   if (bind(sockfd, (struct sockaddr *)&host_addr, sizeof(struct sockaddr)) == -1)
      fatal("Bind失败");

   if (listen(sockfd, 20) == -1)
      fatal("Listen失败");

   while(1) {   
      sin_size = sizeof(struct sockaddr_in);
      new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
      if(new_sockfd == -1)
         fatal("新连接失败");

      handle_connection(new_sockfd, &client_addr);
   }
   return 0;
}

void handle_connection(int sockfd, struct sockaddr_in *client_addr_ptr) {
   unsigned char *ptr, request[500], resource[500];
   int fd, length;
   
   length = recv_line(sockfd, request);
   
   printf("来自%s:%d 的請求  \"%s\"\n", inet_ntoa(client_addr_ptr->sin_addr), ntohs(client_addr_ptr->sin_port), request);

   ptr = strstr(request, " HTTP/"); // 注意第一个字符是空格 
   if(ptr == NULL) { // 找不到HTTP就说明不是一个合法的請求 
      printf(" 非HTTP!\n");
   } else {
      *ptr = 0; //找到了HTTP," HTTP/“ 就结束使命了,在第一个空格处加'\0' 
      ptr = NULL; // 接下来找"GET "或是" HEAD ",若没有找到,ptr设为NULL就有用了 
      if(strncmp(request, "GET ", 4) == 0)  // GET請求
         ptr = request+4; // 請求会是类似于 GET /image.jpg HTTP/1.1"这种形式,就可以理解为什么加4了
      if(strncmp(request, "HEAD ", 5) == 0) // 同理 
         ptr = request+5; // 同理

      if(ptr == NULL) { // 找不到"GET " 或是"HEAD "的任何一个
         printf("\t未知請求!\n");
      } else { // 找到"GET "或"HEAD "中任何一个,就开始处理后续的 比如"GET /image.jpg" 的"/image.jpg"部分
         if (ptr[strlen(ptr) - 1] == '/')  // 若只有一个"/",则默认返回index.html 
            strcat(ptr, "index.html");     
         strcpy(resource, WEBROOT);     // 开始构建一个完整的路径 
         strcat(resource, ptr);         
         fd = open(resource, O_RDONLY, 0); //  试着打开这个文件
         printf("\t打开\'%s\' \t", resource);
         if(fd == -1) { // 没有找到文件 
            printf(" 404 Not Found\n");
            send_string(sockfd, "HTTP/1.0 404 NOT FOUND\r\n");
            send_string(sockfd, "Server: Tiny webserver\r\n\r\n");
            send_string(sockfd, "<html><head><title>404 Not Found</title></head>");
            send_string(sockfd, "<body><h1>URL not found</h1></body></html>\r\n");
         } else {      // 找到文件则发送, 
            printf(" 200 OK\n");
            send_string(sockfd, "HTTP/1.0 200 OK\r\n");
            send_string(sockfd, "Server: Tiny webserver\r\n\r\n");
            if(ptr == request + 4) { // 上面ptr 已经被設定好,现在看ptr如果是GET 命令的话 
               if( (length = get_file_size(fd)) == -1)
                  fatal("取得文件大小失败。");
               if( (ptr = (unsigned char *) malloc(length)) == NULL)
                  fatal("内存的分配失败。");
               read(fd, ptr, length); // 将文件读入内存
               send(sockfd, ptr, length, 0);  // 发送 
               free(ptr); // 释放存储文件的内存 
            }
            close(fd); // 关闭文件 
         } 
      } 
   } 
   shutdown(sockfd, SHUT_RDWR); 
}

int get_file_size(int fd) {
   struct stat stat_struct;

   if(fstat(fd, &stat_struct) == -1)
      return -1;
   return (int) stat_struct.st_size;
}


[ 本帖最后由 madfrogme 于 2012-10-12 23:00 编辑 ]
搜索更多相关主题的帖子: 用户 include void 
2012-10-12 21:41
madfrogme
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:21
帖 子:1160
专家分:1106
注 册:2009-6-24
收藏
得分:0 
这是hacking.h 文件

程序代码:
void fatal(char *message) {
   char error_message[100];

   strcpy(error_message, "[!!] 致命错误:");
   strncat(error_message, message, 83); 
   perror(error_message); 
   exit(-1);
}


void *ec_malloc(unsigned int size) {
   void *ptr; 
   ptr = malloc(size); 
   if(ptr == NULL)
      fatal("ec_malloc()内存分配失败"); 
   return ptr;
}



void dump(const unsigned char *data_buffer, const unsigned int length) {
   unsigned char byte;
   unsigned int i, j;
   for(i=0; i < length; i++) {
      byte = data_buffer[i];
      printf("%02x ", data_buffer[i]);  
      if(((i%16)==15) || (i==length-1)) {
         for(j=0; j < 15-(i%16); j++)
            printf("   ");
         printf("| ");
         for(j=(i-(i%16)); j <= i; j++) {  
            byte = data_buffer[j];
            if((byte > 31) && (byte < 127)) 
               printf("%c", byte);
            else
               printf(".");
         }
         printf("\n"); 
      } 
   } 
}

The quieter you become, the more you can hear
2012-10-12 21:42
madfrogme
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:21
帖 子:1160
专家分:1106
注 册:2009-6-24
收藏
得分:0 
这是hacking-network.h文件
程序代码:
int send_string(int sockfd, unsigned char *buffer) {
   int sent_bytes, bytes_to_send;
   bytes_to_send = strlen(buffer);
   while(bytes_to_send > 0) {
      sent_bytes = send(sockfd, buffer, bytes_to_send, 0);
      if(sent_bytes == -1)
         return 0; // 失敗時には0を返す。
      bytes_to_send -= sent_bytes;
      buffer += sent_bytes;
   }
   return 1; 
}

int recv_line(int sockfd, unsigned char *dest_buffer) {
#define EOL "\r\n" 
#define EOL_SIZE 2
   unsigned char *ptr;
   int eol_matched = 0;

   ptr = dest_buffer;
   while(recv(sockfd, ptr, 1, 0) == 1) { 
      if(*ptr == EOL[eol_matched]) {
         eol_matched++;
         if(eol_matched == EOL_SIZE) { 
            *(ptr+1-EOL_SIZE) = '\0';
            return strlen(dest_buffer); 
         }
      } else {
         eol_matched = 0;
      }
      ptr++;
   }
   return 0;
}

The quieter you become, the more you can hear
2012-10-12 21:44
madfrogme
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:21
帖 子:1160
专家分:1106
注 册:2009-6-24
收藏
得分:0 
$ gcc -o tinyweb tinyweb.c

$ sudo chown root ./tinyweb

$ sudo chmod u+s ./tinyweb




打开浏览器

http://127.0.0.1:50000

http://127.0.0.1:50000/image.jpg

就可以浏览了,只管往webroot文件夹里放文件,来实验显示就可以

The quieter you become, the more you can hear
2012-10-12 21:48
有容就大
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:东土大唐
等 级:版主
威 望:74
帖 子:9048
专家分:14309
注 册:2011-11-11
收藏
得分:0 
哇 厉害 写服务器了!

梅尚程荀
马谭杨奚







                                                       
2012-10-14 15:05
madfrogme
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:21
帖 子:1160
专家分:1106
注 册:2009-6-24
收藏
得分:0 
回复 5楼 有容就大
等过几天可能还有一些好玩的东西看看能不能搞一下,贴出来

The quieter you become, the more you can hear
2012-10-14 18:04
wzj0118
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2011-3-18
收藏
得分:0 
学习了,谢谢
2012-12-27 12:43
xinglinzhang
Rank: 1
等 级:新手上路
帖 子:5
专家分:2
注 册:2013-1-14
收藏
得分:0 
厉害,看得我眼馋
2013-02-26 20:04
快速回复:一个简单的 HTTP 服务器
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.015570 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved