编写简单的WEB服务器
一、背景
我们都知道使用浏览器访问网址的方法,将网址输入进地址框中就会显示出相应的文字、图片、视频等信息。实际上基于socket的客户/服务器原理是相似的,虽然可能承载信息的载体不同,但其背后的原理是基本一致的。通过理解这些原理(关于socket,我上一篇博客分析过),我们就可以编写一个简单的WEB服务器并做检测。
二、基本步骤
实际上基于socket的客户/服务器系统的步骤可以简单的概括为3步:
1、服务器建立服务
2、客户端连接服务器
3、客户端与服务器进行数据交换
三、编写socklib.c文件
这个文件中主要包含了一些常用的函数。便于模块化编程。
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<time.h>
#include<strings.h>
#define HOSTLEN 256
#define BACKLOG 1
int make_server_socket_q(int ,int );
int make_server_socket(int portnum)
{
return make_server_socket_q(portnum,BACKLOG);
}
int make_server_socket_q(int portnum,int backlog)
{
struct sockaddr_in saddr;
struct hostent *hp;
char hostname[HOSTLEN];
int sock_id;
sock_id = socket(PF_INET,SOCK_STREAM,0);
if (sock_id == -1)
return -1;
bzero((void *)&saddr,sizeof(saddr));
gethostname(hostname,HOSTLEN);
hp = gethostbyname(hostname);
bcopy((void *)hp->h_addr,(void *)&saddr.sin_addr,hp->h_length);
saddr.sin_port = htons(portnum);
saddr.sin_family = AF_INET;
if(bind(sock_id,(struct sockaddr *)&saddr,sizeof(saddr)) != 0)
return -1;
if(listen(sock_id,backlog) != 0)
return -1;
return sock_id;
}
int connect_to_server(char *host,int portnum)
{
int sock;
struct sockaddr_in servadd;
struct hostent *hp;
sock = socket(AF_INET,SOCK_STREAM,0);
if(sock == -1)
return -1;
bzero(&servadd,sizeof(servadd));
hp = gethostbyname(host);
if(hp == NULL)
return -1;
bcopy(hp->h_addr,(struct sockaddr *)&servadd.sin_addr,hp->h_length);
servadd.sin_port = htons(portnum);
servadd.sin_family = AF_INET;
if(connect(sock,(struct sockaddr *)&servadd,sizeof(servadd)) != 0)
return -1;
return sock;
}
make_server_socket函数返回一个服务器的socket。
connect_to_server函数返回一个连接后的socket。
四、编写WEB服务器
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
int main(int ac,char *av[])
{
int sock,fd;
FILE *fpin;
char request[BUFSIZ];
if(ac == 1){
fprintf(stderr,"usage:ws portnum\n");
exit(1);
}
sock = make_server_socket(atoi(av[1]));
if(sock == -1)
exit(2);
while(1){
fd = accept(sock,NULL,NULL);
fpin = fdopen(fd,"r");
fgets(request,BUFSIZ,fpin);
printf("got a call:request = %s",request);
read_til_crnl(fpin);
process_rq(request,fd);
fclose(fpin);
}
}
read_til_crnl(FILE *fp)
{
char buf[BUFSIZ];
while(fgets(buf,BUFSIZ,fp) != NULL && strcmp(buf,"\r\n") != 0);
}
process_rq(char *rq,int fd)
{
char cmd[BUFSIZ],arg[BUFSIZ];
if(fork() != 0)
return ;
strcpy(arg,"./");
if(sscanf(rq,"%s %s",cmd,arg+2) != 2)
return ;
if(strcmp(cmd,"GET") != 0)
cannot_do(fd);
else if(not_exist(arg))
do_404(arg,fd);
else if(isadir(arg))
do_ls(arg,fd);
else if(ends_in_cgi(arg))
do_exec(arg,fd);
else
do_cat(arg,fd);
}
header(FILE *fp,char *content_type)
{
fprintf(fp,"HTTP/1.0 200 OK\r\n");
if(content_type)
fprintf(fp,"Content-type:%s\r\n",content_type);
}
cannot_do(int fd)
{
FILE *fp = fdopen(fd,"w");
fprintf(fp,"HTTP/1.0 501 Not Implemented\r\n");
fprintf(fp,"Content-type:text/plain\r\n");
fprintf(fp,"\r\n");
fprintf(fp,"That command is not yet implemented\r\n");
fclose(fp);
}
do_404(char *item,int fd)
{
FILE *fp = fdopen(fd,"w");
fprintf(fp,"HTTP/1.0 404 Not Found\r\n");
fprintf(fp,"Content-type:text/plain\r\n");
fprintf(fp,"\r\n");
fprintf(fp,"The item you requested: %s\r\nis not found\r\n",item);
fclose(fp);
}
isadir(char *f)
{
struct stat info;
return(stat(f,&info) != -1 && S_ISDIR(info.st_mode));
}
not_exist(char *f)
{
struct stat info;
return(stat(f,&info) == -1);
}
do_ls(char *dir,int fd)
{
FILE *fp;
fp = fdopen(fd,"w");
header(fp,"text/plain");
fprintf(fp,"\r\n");
fflush(fp);
dup2(fd,1);
dup2(fd,2);
close(fd);
execlp("ls","ls","-l",dir,NULL);
perror(dir);
exit(1);
}
char *file_type(char *f)
{
char *cp;
if((cp = strrchr(f,'.')) != NULL)
return cp+1;
return "";
}
ends_in_cgi(char *f)
{
return (strcmp(file_type(f),"cgi") == 0);
}
do_exec(char *prog,int fd)
{
FILE *fp;
fp = fdopen(fd,"w");
header(fp,NULL);
fflush(fp);
dup2(fd,1);
dup2(fd,2);
close(fd);
execl(prog,prog,NULL);
perror(prog);
}
do_cat(char *f,int fd)
{
char *extension = file_type(f);
char *content = "text/plain";
FILE *fpsock,*fpfile;
int c;
if(strcmp(extension,"html") == 0)
content = "text/html";
else if(strcmp(extension,"gif") == 0)
content = "image/gif";
else if(strcmp(extension,"jpg") == 0)
content = "image/jpeg";
fpsock = fdopen(fd,"w");
fpfile = fopen(f,"r");
if(fpsock != NULL && fpfile != NULL)
{
header(fpsock,content);
fprintf(fpsock,"\r\n");
while((c = getc(fpfile)) != EOF)
putc(c,fpsock);
fclose(fpfile);
fclose(fpsock);
}
exit(0);
}
五、测试WEB服务器
使用gcc webserv.c socklib.c -o webserv进行编译
接着运行webserv,后面跟端口号(12345)
在浏览器中输入你计算机的主机名:12345
然后后面加上你需要打开的文件或者需要运行的文件
六、总结
WEB服务器与一般的时间查询服务器原理是相通的,都是基于socket的。这里只是简单的编写了WEB服务器。后续还有许多需要接着学习。
编写简单的WEB服务器相关推荐
- 【计算机网络作业】Java UDP聊天 和 Socket编写一个简单的Web服务器
1-1 假设Tom和Jerry利用Java UDP进行聊天,请为他们编写程序.具体如下: (1).Tom和Jerry聊天的双方都应该具有发送端和接收端: (2).利用DatagramSocket与Da ...
- 使用node.js作为简单的Web服务器
我想运行一个非常简单的HTTP服务器. 对example.com每个GET请求都应该将index.html提供给它,但是作为常规HTML页面(即,与阅读普通网页时相同的体验). 使用下面的代码,我可以 ...
- 基于epoll实现简单的web服务器
1. 简介 epoll 是 Linux 平台下特有的一种 I/O 复用模型实现,于 2002 年在 Linux kernel 2.5.44 中被引入.在 epoll 之前,Unix/Linux 平台下 ...
- 利用python编写设计多线程web服务器(计算机网络_自顶向下第六版_第二章1和4的编程作业)
今天翻看自己以前的博客时,发现了这则博客,距今大约也有一年多的时间了,觉得还是蛮有趣的一个作业,于是跟着博客又做了一遍,觉得之前的排版有点不大好,所以此番用markdown 稍微重做些修改更新一下博客 ...
- Linux C简单的web服务器
Linux C简单的web服务器 目录 Linux C简单的web服务器 一.基础类型重命名 二.包裹函数(wrap.h/wrap.c 主要是网络通讯和多线程的包裹函数) 三.服务端程序(web_se ...
- Linux C小项目 —— 简单的web服务器
简单的Web服务器 实现一个基于HTTP通信协议的web服务器.客户端向服务器程序发送所需文件的请求,服务器端分析请求并将文件发送个客户端. 1.整体程序设计 客户端发送所需文件,服务器返回该文件,通 ...
- 用Python建立最简单的web服务器
用Python建立最简单的web服务器 利用Python自带的包可以建立简单的web服务器.在DOS里cd到准备做服务器根目录的路径下,输入命令: python -m Web服务器模块 [端口号,默认 ...
- ipad php mysql_如何用PHP/MySQL为 iOS App 写一个简单的web服务器(译) PART1
原文:http://www.raywenderlich.com/2941/how-to-write-a-simple-phpmysql-web-service-for-an-ios-app 作为一个i ...
- 我的Go语言学习之旅八:创建一个简单的WEB服务器
因为一直在做WEB程序,所以更关注WEB界的发展,这里就用GO做了一个简单的WEB服务器,直接看例子吧 package main import ( "fmt" "net/ ...
最新文章
- Python 三十大实践、建议和技巧(附代码链接)
- hdu4536 水搜索
- JavaScript计算汉明距离(HammingDistance)
- gnu java_GNU/Linux下Java开发环境的安装和配置
- 静态网站任何优化怎么设置_网站关键词怎么设置对网站推广优化有利?
- java 有没有with语句_Java中的try-with-resources语句
- mysqldb mysql config,安装mysqldb python界面时找不到mysql_config
- Eureka覆盖状态
- 查找CSDN误删除博客方法
- html css . doc,html+CSS基础.doc
- UG NX 12 内部草图和外部草图的区别
- PHP 之建行龙支付 - 退款
- CSDN好的blog
- 删除Docker出现: device or resource busy错误
- android mvp设计思想,android MVP 设计模式
- 翰麟教育|教育学人物考点梳理
- 扇贝python课程打卡_Learning by doing——百日“扇贝打卡” 历程展望
- 公司内部网络解决码云配置问题(gitee码云公玥管理)
- 利用电子计算机处理数字化的影像信息,影像诊断习题题库适合复习考试使用
- GoLang之读取文件10种的方法
热门文章
- Scrapy框架学习(四)----CrawlSpider、LinkExtractors、Rule及爬虫示例
- 空间后方交会前方交会 MFC实现 CSU 摄影测量学
- 2022年上期计算机英语复习
- Hydra爆破SSH
- Unity 声音组件 Audio Source(声源)和Audio Listener(声音接收者)
- java区分无线网卡,无线网卡有哪些?无线网卡种类有什么区别?
- 基于java的音乐歌曲网站设计与实现-源码
- 如何在博客主页添加音乐按钮(HTML小试)
- 【软件设计师21天-考点整理】3)计算机系统构成及硬件基础知识
- IT风云15年的那些人、那些事(七)