Chinaunix首页 | 论坛 | 博客
  • 博客访问: 867166
  • 博文数量: 82
  • 博客积分: 2283
  • 博客等级: 大尉
  • 技术积分: 2007
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-15 22:19
文章分类

全部博文(82)

文章存档

2012年(82)

分类: 系统运维

2012-10-05 21:35:37

最近学习了linux网络编程,自己写了一给非常简单的web服务器,他只能回应客户端(browser)取页面命令(GET),能支持 ".html",".jpeg",".png",".gif"格式的文件,没有对任何的服务器脚本语言作处理。以下是源代码:
#include
#include
#include
#include
#include
#include
#include
#define Debug
#define  HEADER\
"HTTP/1.0 %s\r\n"\
"Server: Redhat\r\n"\
"Content-Length: %ld\r\n"
#define  CONTENT_TEXT\
"Content-Type: text/html\r\n\r\n"
#define  CONTENT_JPEG\
"Content-Type: image/jpeg\r\n\r\n"
#define  CONTENT_PNG\
"Content-type: image/png\r\n\r\n"
#define  CONTENT_GIF\
"Content-type: image/gif\r\n\r\n"
#define  HTML_NOTFOUND\
"\n"\
"Error 404\n"\
"\n"\
"

Redhat Server can't find document

"\
" \r\n"
#define  DEFAULT_DOC  "index.html"
#define  WEB_ROOT   "webroot/"
#define  PORT  8000
void  get_path_and_cmd(const char *msg, char *path, char *cmd)
{
int i;
char s[512];

i = 0;
memset(path, 0, sizeof(path));
memset(cmd, 0, sizeof(cmd));
if(msg != NULL){
  while(msg != ' ')
   i++;
  if(msg == ' ')
   strncpy(cmd, msg, i);
  strncpy(s, &msg, strlen(msg)-i);
  i = 0;
  while(s != ' ')
   i++;
  if(s == ' '){
   strncpy(path, s, i);
   path = 0;
  }
}
}
static int send_head(const char *msg, off_t len, const char *path, int fd)
{
char buf[1024], *dot;
int  nwrite;
snprintf(buf, sizeof(buf), HEADER, msg, (long)len);
nwrite = strlen(buf);
if(nwrite != write(fd, buf, nwrite))
  return -1;
dot = strrchr(path, '.');
if(dot != NULL && (strcasecmp(dot, ".jpg") == 0 || strcasecmp(dot, ".jpeg") == 0)){
  nwrite = strlen(CONTENT_JPEG);
  if(nwrite != write(fd, CONTENT_JPEG, nwrite))
   return -1;
}
else if(dot != NULL && (strcasecmp(dot, ".png") == 0)){
  nwrite = strlen(CONTENT_PNG);
  if(nwrite !=(fd, CONTENT_PNG, nwrite))
   return -1;
}
else if(dot != NULL && (strcasecmp(dot, ".gif")) == 0){
  nwrite = strlen(CONTENT_GIF);
  if(nwrite != (fd, CONTENT_GIF, nwrite))
   return -1;
}
else{
  nwrite = strlen(CONTENT_TEXT);
  if(nwrite != write(fd, CONTENT_TEXT, nwrite))
   return -1;
}
return 0;
}
static int hand_request(char *cmd, char *path, int fd)
{
char buf[1024], pathname[512];
FILE *in;
struct stat statbuf;
int  size, flags;
ssize_t  n;
if(strcasecmp(cmd, "get") != 0){
  printf("Unknown request\n");
  return -1;
}
if(strcasecmp(path, "") == 0){
  flags = 0;
  size = strlen(DEFAULT_DOC);
}
else{
  size = strlen(path);
  flags = 1;
}
snprintf(pathname, sizeof(pathname)-1-size, "%s", WEB_ROOT);
if(stat(pathname, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)){
  if(flags)
   strcat(pathname, path);
  else
   strcat(pathname, DEFAULT_DOC);
}
if(stat(pathname, &statbuf) == -1 || (in = fopen(pathname, "rb")) == NULL){
  n = strlen(HTML_NOTFOUND);
  send_head("404 Not Found", n, "", fd);
  if(n != write(fd, HTML_NOTFOUND, n))
   return -1;
}
#ifdef Debug
fprintf(stdout, "path: %s\n", pathname);
#endif
send_head("200 OK", statbuf.st_size, pathname, fd);
while((n = fread(buf, 1, sizeof(buf), in)) > 0){
  if(n != write(fd, buf, n))
   return -1;
}
return 0;
}
int main(void)
{
char msg[4096], cmd[8], path[512];
ssize_t  nrcv;
int  listenfd, connfd;
struct sockaddr_in  servaddr;
char host[128] = "//";
if(gethostname(&host[2], sizeof(host)-6) == -1)
  return -1;
strcat(host, "8000");
printf("Connect to host \"%s\"\n",host);
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if(listenfd < 0){
  fprintf(stderr, "Soket error\n");
  exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
  fprintf(stderr, "Bind error\n");
  exit(1);
}
if(listen(listenfd, 5) < 0){
  fprintf(stderr, "Listen error\n");
  exit(1);
}
for(;;){
  fprintf(stdout, "waiting....\n");
  connfd = accept(listenfd, NULL, NULL);
  if(connfd < 0){
   fprintf(stderr, "accept error\n");
   exit(1);
  }
  if(read(connfd, msg, sizeof(msg)-1) <= 0){
#ifdef Debug
   fprintf(stderr, "\nUnkown request\t\t");
#endif
   return -1;
  }
  msg[strlen(msg)] = 0;
#ifdef Debug
  fprintf(stderr, "\nheader: %s\t", msg);
#endif
  get_path_and_cmd(msg, path, cmd);
  hand_request(cmd, path, connfd);
  close(connfd);
}
close(listenfd);
return 0;
}
里面基本没有对错误进行处理,只是简单的返回-1,要便于调试,可以用条件编译,打印出相关的信息,或许你们有更好的方法来实现一个简单的wen server,不妨拿出来大家一起分享。
我的运行环境是Windows xp 上VMware workstation中的 Redhat9.0。
Redhat9.0的ip地址是192.168.37.128  选择了8000 端口
webroot 的工作目录是/home/wanghui/netinet
用gcc编译,并后台运行
$ gcc -owebserver webserver.c
$ ./webserver&
在Windows xp 中打开IE browser 在地址栏中输入 回车
即可以看到/home/wanghui/network/webroot/中的index.html页面了(如果有的话)。在
Redhat9.0的终端中可以看到browser发送的请求如下:
header: GET / HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: 192.168.37.128:8000
Connection: Keep-Alive
t: 192.168.37.128:8000
Connection: Keep-Alive
;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer:
rer:
no-cache
        path: webroot/index.html
waiting....
本来是要在我们宿舍建一个局域网的,以我的机子作为服务器,但我得机子比较烂,不知是主板上的南桥有问题还是那几个pci槽全都不管用
了,插上网线,本地连接还是一把红叉,很无赖,以前是能上网的。
本人没有学习jsp,php, asp等服务器脚本语言,服务器是怎样去解释这些脚本的,我是一点都不清楚,所以也就无法要它支持他们
了,有兴趣的可以一起学习讨论,一起来完善这个服务程序,本来想去看apache的源码,太大了,代码组织也很复杂,估计很难看懂
的(:-)。
阅读(2406) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~