一、背景

我们都知道使用浏览器访问网址的方法,将网址输入进地址框中就会显示出相应的文字、图片、视频等信息。实际上基于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服务器相关推荐

  1. 【计算机网络作业】Java UDP聊天 和 Socket编写一个简单的Web服务器

    1-1 假设Tom和Jerry利用Java UDP进行聊天,请为他们编写程序.具体如下: (1).Tom和Jerry聊天的双方都应该具有发送端和接收端: (2).利用DatagramSocket与Da ...

  2. 使用node.js作为简单的Web服务器

    我想运行一个非常简单的HTTP服务器. 对example.com每个GET请求都应该将index.html提供给它,但是作为常规HTML页面(即,与阅读普通网页时相同的体验). 使用下面的代码,我可以 ...

  3. 基于epoll实现简单的web服务器

    1. 简介 epoll 是 Linux 平台下特有的一种 I/O 复用模型实现,于 2002 年在 Linux kernel 2.5.44 中被引入.在 epoll 之前,Unix/Linux 平台下 ...

  4. 利用python编写设计多线程web服务器(计算机网络_自顶向下第六版_第二章1和4的编程作业)

    今天翻看自己以前的博客时,发现了这则博客,距今大约也有一年多的时间了,觉得还是蛮有趣的一个作业,于是跟着博客又做了一遍,觉得之前的排版有点不大好,所以此番用markdown 稍微重做些修改更新一下博客 ...

  5. Linux C简单的web服务器

    Linux C简单的web服务器 目录 Linux C简单的web服务器 一.基础类型重命名 二.包裹函数(wrap.h/wrap.c 主要是网络通讯和多线程的包裹函数) 三.服务端程序(web_se ...

  6. Linux C小项目 —— 简单的web服务器

    简单的Web服务器 实现一个基于HTTP通信协议的web服务器.客户端向服务器程序发送所需文件的请求,服务器端分析请求并将文件发送个客户端. 1.整体程序设计 客户端发送所需文件,服务器返回该文件,通 ...

  7. 用Python建立最简单的web服务器

    用Python建立最简单的web服务器 利用Python自带的包可以建立简单的web服务器.在DOS里cd到准备做服务器根目录的路径下,输入命令: python -m Web服务器模块 [端口号,默认 ...

  8. 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 ...

  9. 我的Go语言学习之旅八:创建一个简单的WEB服务器

    因为一直在做WEB程序,所以更关注WEB界的发展,这里就用GO做了一个简单的WEB服务器,直接看例子吧 package main import ( "fmt" "net/ ...

最新文章

  1. Python 三十大实践、建议和技巧(附代码链接)
  2. hdu4536 水搜索
  3. JavaScript计算汉明距离(HammingDistance)
  4. gnu java_GNU/Linux下Java开发环境的安装和配置
  5. 静态网站任何优化怎么设置_网站关键词怎么设置对网站推广优化有利?
  6. java 有没有with语句_Java中的try-with-resources语句
  7. mysqldb mysql config,安装mysqldb python界面时找不到mysql_config
  8. Eureka覆盖状态
  9. 查找CSDN误删除博客方法
  10. html css . doc,html+CSS基础.doc
  11. UG NX 12 内部草图和外部草图的区别
  12. PHP 之建行龙支付 - 退款
  13. CSDN好的blog
  14. 删除Docker出现: device or resource busy错误
  15. android mvp设计思想,android MVP 设计模式
  16. 翰麟教育|教育学人物考点梳理
  17. 扇贝python课程打卡_Learning by doing——百日“扇贝打卡” 历程展望
  18. 公司内部网络解决码云配置问题(gitee码云公玥管理)
  19. 利用电子计算机处理数字化的影像信息,影像诊断习题题库适合复习考试使用
  20. GoLang之读取文件10种的方法

热门文章

  1. Scrapy框架学习(四)----CrawlSpider、LinkExtractors、Rule及爬虫示例
  2. 空间后方交会前方交会 MFC实现 CSU 摄影测量学
  3. 2022年上期计算机英语复习
  4. Hydra爆破SSH
  5. Unity 声音组件 Audio Source(声源)和Audio Listener(声音接收者)
  6. java区分无线网卡,无线网卡有哪些?无线网卡种类有什么区别?
  7. 基于java的音乐歌曲网站设计与实现-源码
  8. 如何在博客主页添加音乐按钮(HTML小试)
  9. 【软件设计师21天-考点整理】3)计算机系统构成及硬件基础知识
  10. IT风云15年的那些人、那些事(七)