您的位置:首页 > 其它

利用socket编写简单的web 服务器

2009-04-30 18:26 519 查看
项目名称:编写简单的web 服务器
主要目的:练习socket 编程、socket并发服务器

可行性分析:
时间 :2天;
涉及知识:socket 编程、进程或线程的应用、web 服务器的服务形式

需求分析:
1、客户端向服务器发送请求;
2、服务器对请求进行应答;
3、服务器对不规范的域名进行纠正,发送到客户端;
4、服务器遍历目录,若没找到请求的文件或目录,提示客户端东西没找到
5、若存在,服务器向客户端发送请求的服务;
6、关闭链接
7、可同时进行多客户端的连接
8、动态功能,请求的数据具有新的位置且更改是永久的(保留功能)。

概要设计:
客户端用IE代替
服务器端阻塞等待
clientHandler()处理收发
详细设计:
1、写一个服务器程序main.c;
2、clientHandler()函数:
取得客户端请求的内容;
从取得内容中分离出请求的文件路径;
遍历查找客户端请求的内容,在服务器端是否存在;
若存在,则把内容读到客户端
不存在,提示客户端
编码:
在链接http://download.csdn.net/source/1261937

测试:
用 网管大师(追踪者)-数据包捕获器 V 1.281 专用版 抓包查看各种数据
(网管大师(追踪者)-数据包捕获器 V 1.281 专用版.rar 链接http://download.csdn.net/source/1261950
打开保存的Google 网页、ifeng 网页
打开一些文本文件
打开一些图片

维护:


相关知识:
stat 函数:取得文件的属性
例:
#include <sys/stat.h>
#inlcude <unistd.h>
int main()
{
struct stat buf;
stat("/etc/passwd", &buf);
printf("/etc/passwd file size = %d /n", buf.st_size);
}

http状态指示码查看 http://blog.csdn.net/xiaozhi_su/archive/2009/04/30/4140426.aspx
客户端发给服务器的请求信息(其第一句必须要有,且其行末必须是回车换行):

GET /index.html HTTP/1.1 // 其中index.html 是请求的文件
Accept:image/gif.image/jpeg,*/*
Accept-Language:zh-cn
Connection:Keep-Alive
Host:localhost
Accept-Encoding:gzip,deflate

服务器发给客户端的应答信息:(可选的)
char *resp_head = "HTTP/1.1 200 OK/r/n" /
"Content-Type: text/html/r/n" /
"Content-Length:%ld/r/n" /
"/r/n";
char *not_found = "HTTP/1.1 404 Not Found/r/n" /
"Content-Type: text/html/r/n" /
"Content-Length: 40/r/n" /
"/r/n" /
"<HTML><BODY>File not found</BODY></HTML>";
char *bad_request = "HTTP/1.1 400 Bad Request/r/n" /
"Content-Type: text/html/r/n" /
"Content-Length: 39/r/n" /
"/r/n" /
"<h1>Bad Request (Invalid Hostname)</h1>";
char *moved_permanently =
"HTTP/1.1 301 Moved Permanently/r/n"/
"Content-Length: 147/r/n" /
"Content-Type: text/html/r/n" /
"Location: %s/r/n" /
"/r/n" /
"<head><title>Document Moved</title></head><body><h1>Object Moved</h1>This document may be found <a HREF=/"%s/">here</a></body>";

用 fprintf 或 sprintf 函数往char *resp_head 写入格式化数据 %ld
fprintf用法:
FILE *fp = fdopen(connfd, “w”); //connfd 为由 accept 返回的句柄,转换为文件指针
fprintf(fp, resp_head, buf.st_size); //buf.st_size 由stat 函数取得
fflush(fp); // 冲出到客户端

Sprintf用法:
Char buf[4096];
sprintf(buf, resp_head, buf.st_size); // 注意buf 元素个数要比 strlen(resp_head) 大
write(connfd, buf, strlen(buf));

用进程实现并发服务器的核心代码:

先要理解的两点:
关闭socket创建的套接字将导致服务器无法继续接受新的连接,但不会影响已经建立的连接
关闭accept返回的套接字将导致它所代表的连接被关闭,但不会影响服务器的监听
......
if((pid = fork()) == 0)
{
// Child close listening socket
close(sockfd);
ClientHandler(&connfd);
// Process done with this client, close it
close(connfd);
// Child exit
exit(0);
}
else
{
// Parent close the accepted connection
close(connfd);
}

用线程实现的并发服务器核心代码
void *Client_Process(void *arg)// 客户端服务程序
{
int acptSock = (int)arg;
ClientHandler(&acptSock);
close(acptSock);
return;
}


acptSock = accept(lstnSocket,
(struct sockaddr *)&pin,
&address_size);
if(acptSock > 0)
{
pthread_create(&thread_id, NULL,
(void *)Client_Process,
(void *)acptSock);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: