- 浏览: 508792 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
jkxydp:
算法运行的结果根本就不对。
BM算法. -
soarwindzhang:
感谢博主的分享,我今天看了您的UFSET非递归的路径压缩时感觉 ...
并查集 -
zhangning290:
楼主好像只考虑了坏字符规则,。没有考虑好后缀
BM算法. -
lsm0622:
文字描述有错误 误导新学者
求有向图的强连通分量(scc):Tarjan算法 -
knightchen:
博主,你太强了!这篇文章对我学习C++多线程很有帮助!谢谢
并发学习之一_windows下ZThread在CodeBlocks上的安装与配置
1,一个静态内容的http事务:
kmplayer@kmplayer:~$
//客户端请求
telnet www.baidu.com 80
//网络应答
Trying 119.75.213.51...
Connected to www.a.shifen.com.
Escape character is '^]'.
//HTTP请求 形式:<method><uri><version>
GET / HTTP/1.1
host: www.baidu.com
//空行表示请求报头的结束
//HTTP响应 形式:<version><status conde><status message>
HTTP/1.1 200 OK
Date: Fri, 14 May 2010 04:03:45 GMT
Server: BWS/1.0
Content-Length: 3521
Content-Type: text/html;charset=gb2312
Cache-Control: private
Expires: Fri, 14 May 2010 04:03:45 GMT
Set-Cookie: BAIDUID=C08D8C83B7861ACEC2317256C4D81F78:FG=1; expires=Fri, 14-May-40 04:03:45 GMT; path=/; domain=.baidu.com
P3P: CP=" OTI DSP COR IVA OUR IND COM "
//内容
2,
CGI的参数放在环境变量QUERY_STRING中。
"?"分隔文件名和请求参数。"&"分隔参数。
如:
http://km.com:80/cgi-bin/adder?34&54
一个简单的CGI程序演示:
3,HTTP 1.1支持的状态代码
100 Continue 初始的请求已经接受,客户应当继续发送请求的其余部分
101 Switching Protocols 服务器将遵从客户的请求转换到另外一种协议
200 OK 一切正常,对GET和POST请求的应答文档跟在后面。
201 Created 服务器已经创建了文档,Location头给出了它的URL。
202 Accepted 已经接受请求,但处理尚未完成。
203 Non-Authoritative Information 文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝
204 No Content 没有新文档,浏览器应该继续显示原来的文档。如果用户定期地刷新页面,而Servlet可以确定用户文档足够新,这个状态代码是很有用的
205 Reset Content 没有新的内容,但浏览器应该重置它所显示的内容。用来强制浏览器清除表单输入内容
206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它
300 Multiple Choices 客户请求的文档可以在多个位置找到,这些位置已经在返回的文档内列出。如果服务器要提出优先选择,则应该在Location应答头指明。
301 Moved Permanently 客户请求的文档在其他地方,新的URL在Location头中给出,浏览器应该自动地访问新的URL。
302 Found 类似于301,但新的URL应该被视为临时性的替代,而不是永久性的。
303 See Other 类似于301/302,不同之处在于,如果原来的请求是POST,Location头指定的重定向目标文档应该通过GET提取
304 Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。
305 Use Proxy 客户请求的文档应该通过Location头所指明的代理服务器提取
307 Temporary Redirect 和302(Found)相同。许多浏览器会错误地响应302应答进行重定向,即使原来的请求是POST,即使它实际上只能在POST请求的应答是303时才能重定向。由于这个原因,HTTP 1.1新增了307,以便更加清除地区分几个状态代码:当出现303应答时,浏览器可以跟随重定向的GET和POST请求;如果是307应答,则浏览器只能跟随对GET请求的重定向。
400 Bad Request 请求出现语法错误。
401 Unauthorized 客户试图未经授权访问受密码保护的页面。应答中会包含一个WWW-Authenticate头,浏览器据此显示用户名字/密码对话框,然后在填写合适的Authorization头后再次发出请求。
403 Forbidden 资源不可用。
404 Not Found 无法找到指定位置的资源
405 Method Not Allowed 请求方法(GET、POST、HEAD、DELETE、PUT、TRACE等)对指定的资源不适用。
406 Not Acceptable 指定的资源已经找到,但它的MIME类型和客户在Accpet头中所指定的不兼容
407 Proxy Authentication Required 类似于401,表示客户必须先经过代理服务器的授权。
408 Request Timeout 在服务器许可的等待时间内,客户一直没有发出任何请求。客户可以在以后重复同一请求。
409 Conflict 通常和PUT请求有关。由于请求和资源的当前状态相冲突,因此请求不能成功。
410 Gone 所请求的文档已经不再可用,而且服务器不知道应该重定向到哪一个地址。它和404的不同在于,返回407表示文档永久地离开了指定的位置,而404表示由于未知的原因文档不可用。
411 Length Required 服务器不能处理请求,除非客户发送一个Content-Length头。
412 Precondition Failed 请求头中指定的一些前提条件失败
413 Request Entity Too Large 目标文档的大小超过服务器当前愿意处理的大小。如果服务器认为自己能够稍后再处理该请求,则应该提供一个Retry-After头
414 Request URI Too Long URI太长
416 Requested Range Not Satisfiable 服务器不能满足客户在请求中指定的Range头
500 Internal Server Error 服务器遇到了意料不到的情况,不能完成客户的请求
501 Not Implemented 服务器不支持实现请求所需要的功能。例如,客户发出了一个服务器不支持的PUT请求
502 Bad Gateway 服务器作为网关或者代理时,为了完成请求访问下一个服务器,但该服务器返回了非法的应答
503 Service Unavailable 服务器由于维护或者负载过重未能应答。例如,Servlet可能在数据库连接池已满的情况下返回503。服务器返回503时可以提供一个Retry-After头
504 Gateway Timeout 由作为代理或网关的服务器使用,表示不能及时地从远程服务器获得应答
505 HTTP Version Not Supported 服务器不支持请求中所指明的HTTP版本
4,集线器不加分辨地将一个端口收到的位复制到其他所有的端口上,因此,每台主机都能看到每个位。
5,internet思想的精髓:封装。
6,套接字典型的是作为系统调用实现的,系统会陷入内核,调用内核模式的TCP/IP函数。
7,网络字节顺序:总是大端法。
实例:讲一个16进制数,转换为IP
8,检索并打印DNS主机条目。
9,套接字:
内核角度:通信的端点
程序角度:相应描述符的打开文件。
10,服务器实例代码:
头文件:webh.h
系统IO文件:stu_rio.c
进程文件:stu_fork.c
套接字文件:stu_socket.c
main文件:main.c
kmplayer@kmplayer:~$
//客户端请求
telnet www.baidu.com 80
//网络应答
Trying 119.75.213.51...
Connected to www.a.shifen.com.
Escape character is '^]'.
//HTTP请求 形式:<method><uri><version>
GET / HTTP/1.1
host: www.baidu.com
//空行表示请求报头的结束
//HTTP响应 形式:<version><status conde><status message>
HTTP/1.1 200 OK
Date: Fri, 14 May 2010 04:03:45 GMT
Server: BWS/1.0
Content-Length: 3521
Content-Type: text/html;charset=gb2312
Cache-Control: private
Expires: Fri, 14 May 2010 04:03:45 GMT
Set-Cookie: BAIDUID=C08D8C83B7861ACEC2317256C4D81F78:FG=1; expires=Fri, 14-May-40 04:03:45 GMT; path=/; domain=.baidu.com
P3P: CP=" OTI DSP COR IVA OUR IND COM "
//内容
2,
CGI的参数放在环境变量QUERY_STRING中。
"?"分隔文件名和请求参数。"&"分隔参数。
如:
http://km.com:80/cgi-bin/adder?34&54
一个简单的CGI程序演示:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #define MAXLINE 8192 /* max text line length */ int main(void) { char *buf, *p; char arg1[MAXLINE], arg2[MAXLINE], content[MAXLINE]; int n1=0, n2=0; char buf2[]="34&54"; /* Extract the two arguments */ //if ((buf = getenv("QUERY_STRING")) != NULL) { p = strchr(buf2, '&'); *p = '\0'; strcpy(arg1, buf2); strcpy(arg2, p+1); n1 = atoi(arg1); n2 = atoi(arg2); } /* Make the response body */ sprintf(content, "Welcome to add.com: "); sprintf(content, "%sTHE Internet addition portal.\r\n<p>", content); sprintf(content, "%sThe answer is: %d + %d = %d\r\n<p>", content, n1, n2, n1 + n2); sprintf(content, "%sThanks for visiting!\r\n", content); /* Generate the HTTP response */ printf("Content-length: %d\r\n", (int)strlen(content)); printf("Content-type: text/html\r\n\r\n"); printf("%s", content); fflush(stdout); exit(0); }
3,HTTP 1.1支持的状态代码
100 Continue 初始的请求已经接受,客户应当继续发送请求的其余部分
101 Switching Protocols 服务器将遵从客户的请求转换到另外一种协议
200 OK 一切正常,对GET和POST请求的应答文档跟在后面。
201 Created 服务器已经创建了文档,Location头给出了它的URL。
202 Accepted 已经接受请求,但处理尚未完成。
203 Non-Authoritative Information 文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝
204 No Content 没有新文档,浏览器应该继续显示原来的文档。如果用户定期地刷新页面,而Servlet可以确定用户文档足够新,这个状态代码是很有用的
205 Reset Content 没有新的内容,但浏览器应该重置它所显示的内容。用来强制浏览器清除表单输入内容
206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它
300 Multiple Choices 客户请求的文档可以在多个位置找到,这些位置已经在返回的文档内列出。如果服务器要提出优先选择,则应该在Location应答头指明。
301 Moved Permanently 客户请求的文档在其他地方,新的URL在Location头中给出,浏览器应该自动地访问新的URL。
302 Found 类似于301,但新的URL应该被视为临时性的替代,而不是永久性的。
303 See Other 类似于301/302,不同之处在于,如果原来的请求是POST,Location头指定的重定向目标文档应该通过GET提取
304 Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。
305 Use Proxy 客户请求的文档应该通过Location头所指明的代理服务器提取
307 Temporary Redirect 和302(Found)相同。许多浏览器会错误地响应302应答进行重定向,即使原来的请求是POST,即使它实际上只能在POST请求的应答是303时才能重定向。由于这个原因,HTTP 1.1新增了307,以便更加清除地区分几个状态代码:当出现303应答时,浏览器可以跟随重定向的GET和POST请求;如果是307应答,则浏览器只能跟随对GET请求的重定向。
400 Bad Request 请求出现语法错误。
401 Unauthorized 客户试图未经授权访问受密码保护的页面。应答中会包含一个WWW-Authenticate头,浏览器据此显示用户名字/密码对话框,然后在填写合适的Authorization头后再次发出请求。
403 Forbidden 资源不可用。
404 Not Found 无法找到指定位置的资源
405 Method Not Allowed 请求方法(GET、POST、HEAD、DELETE、PUT、TRACE等)对指定的资源不适用。
406 Not Acceptable 指定的资源已经找到,但它的MIME类型和客户在Accpet头中所指定的不兼容
407 Proxy Authentication Required 类似于401,表示客户必须先经过代理服务器的授权。
408 Request Timeout 在服务器许可的等待时间内,客户一直没有发出任何请求。客户可以在以后重复同一请求。
409 Conflict 通常和PUT请求有关。由于请求和资源的当前状态相冲突,因此请求不能成功。
410 Gone 所请求的文档已经不再可用,而且服务器不知道应该重定向到哪一个地址。它和404的不同在于,返回407表示文档永久地离开了指定的位置,而404表示由于未知的原因文档不可用。
411 Length Required 服务器不能处理请求,除非客户发送一个Content-Length头。
412 Precondition Failed 请求头中指定的一些前提条件失败
413 Request Entity Too Large 目标文档的大小超过服务器当前愿意处理的大小。如果服务器认为自己能够稍后再处理该请求,则应该提供一个Retry-After头
414 Request URI Too Long URI太长
416 Requested Range Not Satisfiable 服务器不能满足客户在请求中指定的Range头
500 Internal Server Error 服务器遇到了意料不到的情况,不能完成客户的请求
501 Not Implemented 服务器不支持实现请求所需要的功能。例如,客户发出了一个服务器不支持的PUT请求
502 Bad Gateway 服务器作为网关或者代理时,为了完成请求访问下一个服务器,但该服务器返回了非法的应答
503 Service Unavailable 服务器由于维护或者负载过重未能应答。例如,Servlet可能在数据库连接池已满的情况下返回503。服务器返回503时可以提供一个Retry-After头
504 Gateway Timeout 由作为代理或网关的服务器使用,表示不能及时地从远程服务器获得应答
505 HTTP Version Not Supported 服务器不支持请求中所指明的HTTP版本
4,集线器不加分辨地将一个端口收到的位复制到其他所有的端口上,因此,每台主机都能看到每个位。
5,internet思想的精髓:封装。
6,套接字典型的是作为系统调用实现的,系统会陷入内核,调用内核模式的TCP/IP函数。
7,网络字节顺序:总是大端法。
实例:讲一个16进制数,转换为IP
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(int argc, char** argv) { struct in_addr inaddr; unsigned int addr; if (argc != 2) { fprintf(stderr, "usage: %s <hex num>\n", argv[0]); exit(0); } sscanf(argv[1], "%x", &addr); inaddr.s_addr=htonl(addr); printf("%s\n", inet_ntoa(inaddr)); return 0; }
8,检索并打印DNS主机条目。
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> void dns_error(char *msg) /* dns-style error */ { fprintf(stderr, "%s: DNS error %d\n", msg, h_errno); exit(0); } struct hostent *Gethostbyname(const char *name) { struct hostent *p; if ((p = gethostbyname(name)) == NULL) dns_error("Gethostbyname error"); return p; } struct hostent *Gethostbyaddr(const char *addr, int len, int type) { struct hostent *p; if ((p = gethostbyaddr(addr, len, type)) == NULL) dns_error("Gethostbyaddr error"); return p; } int main() { char **pp; struct in_addr addr; struct hostent *hostp; char domain[]="www.sina.com.cn";//"127.0.0.1";//"kmplayer";//"www.baidu.com"; if (inet_aton(domain, &addr) != 0) hostp = Gethostbyaddr((const char *)&addr, sizeof(addr), AF_INET); else hostp = Gethostbyname(domain); printf("official hostname: %s\n", hostp->h_name); //link:保存所有的主机别名 for (pp = hostp->h_aliases; *pp != NULL; pp++) printf("alias: %s\n", *pp); //link:保存所有的IP地址 for (pp = hostp->h_addr_list; *pp != NULL; pp++) { addr.s_addr = ((struct in_addr *)*pp)->s_addr; printf("address: %s\n", inet_ntoa(addr)); } exit(0); }
9,套接字:
内核角度:通信的端点
程序角度:相应描述符的打开文件。
10,服务器实例代码:
头文件:webh.h
#ifndef WEBH_INCLUDED #define WEBH_INCLUDED #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include<sys/wait.h> #define MAXLINE 8192 /* max text line length */ #define MAXBUF 8192 /* max I/O buffer size */ #define LISTENQ 1024 /* second argument to listen() */ extern char **environ; /* defined by libc */ #define RIO_BUFSIZE 8192 typedef struct { int rio_fd; /* descriptor for this internal buf */ int rio_cnt; /* unread bytes in internal buf */ char *rio_bufptr; /* next unread byte in internal buf */ char rio_buf[RIO_BUFSIZE]; /* internal buffer */ } rio_t; void unix_error(char* msg); void dns_error(char *msg); int Open(const char *pathname, int flags, mode_t mode); void Rio_readinitb(rio_t *rp, int fd); void Rio_writen(int fd, void *usrbuf, size_t n); ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen); void Close(int fd); int Dup2(int fd1, int fd2); void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); void Munmap(void *start, size_t length); int Open_listenfd(int port); int Accept(int s, struct sockaddr *addr, socklen_t *addrlen); pid_t Fork(void); void Execve(const char *filename, char *const argv[], char *const envp[]); pid_t Wait(int *status); #endif // WEBH_INCLUDED
系统IO文件:stu_rio.c
#include "webh.h" void unix_error(char* msg) { fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(0); } int Open(const char *pathname, int flags, mode_t mode) { int rc; if ((rc = open(pathname, flags, mode)) < 0) unix_error("Open error"); return rc; } void Close(int fd) { int rc; if ((rc = close(fd)) < 0) unix_error("Close error"); } ssize_t Read(int fd, void *buf, size_t count) { ssize_t rc; if ((rc = read(fd, buf, count)) < 0) unix_error("Read error"); return rc; } ssize_t Write(int fd, const void *buf, size_t count) { ssize_t rc; if ((rc = write(fd, buf, count)) < 0) unix_error("Write error"); return rc; } int Dup2(int fd1, int fd2) { int rc; if ((rc = dup2(fd1, fd2)) < 0) unix_error("Dup2 error"); return rc; } /* rio_readn 和 rio_writen可以在存储器和文件之间直接传送数据。 对同一个描述符号,可以任意交错地调用rio_readn 和 rio_writen */ ssize_t rio_readn(int fd, void* usrbuf, size_t n) { size_t nleft = n; ssize_t nread; char* bufp = usrbuf; while ( nleft > 0) { if ((nread = read(fd, bufp, nleft)) < 0) { if (errno == EINTR) //被信号中断,需要重新调用 nread = 0; else return -1; //出错 } else if (nread == 0) break; //EOF 返回不足值 nleft -= nread; bufp += nread; } return (n-nleft); } //不会返回不足值 ssize_t rio_writen(int fd, void* usrbuf, size_t n) { size_t nleft = n; ssize_t nwritten; char* bufp = usrbuf; while ( nleft > 0) { if ((nwritten = write(fd, bufp, nleft)) <= 0) { if (errno == EINTR) //被信号中断,需要重新调用 nwritten = 0; else return -1; } nleft -= nwritten; bufp += nwritten; } return n; } //rio的带缓冲的输入输出函数 void rio_readinitb(rio_t* rp, int fd) { rp->rio_fd = fd; rp->rio_cnt = 0; rp->rio_bufptr = rp->rio_buf; } //rio_read 用来替代read static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n) { int cnt; while (rp->rio_cnt <= 0) //缓冲区空了 { rp->rio_cnt = read (rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf)); if (rp->rio_cnt < 0) { if (errno != EINTR) return -1; } else if (rp->rio_cnt == 0) //EOF return 0; else rp->rio_bufptr = rp->rio_buf; } cnt = (rp->rio_cnt < n? rp->rio_cnt:n); memcpy(usrbuf, rp->rio_bufptr, cnt); // 缓冲区中取出 rp->rio_bufptr += cnt; rp->rio_cnt -= cnt; return cnt; } /*一次读入一行*/ ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen) { int n, rc; char c, *bufp = usrbuf; for (n = 1; n < maxlen; n++) /*最多读 maxlen-1次*/ { if ((rc = rio_read(rp, &c, 1)) == 1) { *bufp++ = c; if (c == '\n') /*读完一行*/ break; } else if (rc == 0) /*得到0*/ { if (n == 1) return 0; /* EOF, no data read */ else break; /* EOF, some data was read */ } else return -1; /* error */ } *bufp = '\0'; /*行结束标记*/ return n; } /*rio带缓冲的读*/ ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n) { size_t nleft = n; ssize_t nread; char *bufp = usrbuf; while (nleft > 0) { if ((nread = rio_read(rp, bufp, nleft)) < 0) { if (errno == EINTR) /* interrupted by sig handler return */ nread = 0; /* call read() again */ else return -1; /* errno set by read() */ } else if (nread == 0) break; /* EOF */ nleft -= nread; bufp += nread; } return (n - nleft); /* return >= 0 */ } /********************************** * Wrappers for robust I/O routines 增加了出错处理 **********************************/ ssize_t Rio_readn(int fd, void *ptr, size_t nbytes) { ssize_t n; if ((n = rio_readn(fd, ptr, nbytes)) < 0) unix_error("Rio_readn error"); return n; } void Rio_writen(int fd, void *usrbuf, size_t n) { if (rio_writen(fd, usrbuf, n) != n) unix_error("Rio_writen error"); } void Rio_readinitb(rio_t *rp, int fd) { rio_readinitb(rp, fd); } ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n) { ssize_t rc; if ((rc = rio_readnb(rp, usrbuf, n)) < 0) unix_error("Rio_readnb error"); return rc; } ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen) { ssize_t rc; if ((rc = rio_readlineb(rp, usrbuf, maxlen)) < 0) unix_error("Rio_readlineb error"); return rc; }
进程文件:stu_fork.c
#include "webh.h" pid_t Fork(void) { pid_t pid; if ((pid = fork()) < 0) unix_error("Fork error"); return pid; } /* $end forkwrapper */ void Execve(const char *filename, char *const argv[], char *const envp[]) { if (execve(filename, argv, envp) < 0) unix_error("Execve error"); } /* $begin wait */ pid_t Wait(int *status) { pid_t pid; if ((pid = wait(status)) < 0) unix_error("Wait error"); return pid; } 内存操作文件: #include "webh.h" void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { void *ptr; if ((ptr = mmap(addr, len, prot, flags, fd, offset)) == ((void *) -1)) unix_error("mmap error"); return(ptr); } void Munmap(void *start, size_t length) { if (munmap(start, length) < 0) unix_error("munmap error"); }
套接字文件:stu_socket.c
#include "webh.h" void dns_error(char *msg) /* dns-style error */ { fprintf(stderr, "%s: DNS error %d\n", msg, h_errno); exit(0); } int Socket(int domain, int type, int protocol) { int rc; if ((rc = socket(domain, type, protocol)) < 0) unix_error("Socket error"); return rc; } void Setsockopt(int s, int level, int optname, const void *optval, int optlen) { int rc; if ((rc = setsockopt(s, level, optname, optval, optlen)) < 0) unix_error("Setsockopt error"); } void Bind(int sockfd, struct sockaddr *my_addr, int addrlen) { int rc; if ((rc = bind(sockfd, my_addr, addrlen)) < 0) unix_error("Bind error"); } void Listen(int s, int backlog) { int rc; if ((rc = listen(s, backlog)) < 0) unix_error("Listen error"); } int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { int rc; if ((rc = accept(s, addr, addrlen)) < 0) unix_error("Accept error"); return rc; } void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen) { int rc; if ((rc = connect(sockfd, serv_addr, addrlen)) < 0) unix_error("Connect error"); } //封装socket和connect int open_clientfd(char *hostname, int port) { int clientfd; struct hostent *hp; struct sockaddr_in serveraddr; if ((clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1; /* check errno for cause of error */ if ((hp = gethostbyname(hostname)) == NULL) return -2; /* DNS出错*/ bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; //功能:将字符串src的前n个字节复制到dest //说明:bcopy不检查字符串中的空字节NULL,函数没有返回值。 bcopy((char *)hp->h_addr_list[0],(char *)&serveraddr.sin_addr.s_addr, hp->h_length); serveraddr.sin_port = htons(port); /* Establish a connection with the server */ if (connect(clientfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) return -1; return clientfd; } //打开和返回一个监听描述符 int open_listenfd(int port) { int listenfd, optval=1; struct sockaddr_in serveraddr; /* Create a socket descriptor */ if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1; /* Eliminates "Address already in use" error from bind. */ //重用bind地址,防止服务器重启可能出错。 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)) < 0) return -1; /* Listenfd will be an endpoint for all requests to port on any IP address for this host */ bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons((unsigned short)port); if (bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) return -1; /* Make it a listening socket ready to accept connection requests */ if (listen(listenfd, LISTENQ) < 0) return -1; return listenfd; } int Open_listenfd(int port) { int rc; if ((rc = open_listenfd(port)) < 0) unix_error("Open_listenfd error"); return rc; }
main文件:main.c
#include "webh.h" void read_requesthdrs(rio_t* rp) { char buf[MAXLINE]; Rio_readlineb(rp, buf, MAXLINE); while(strcmp(buf, "\r\n")) { //line:netp:readhdrs:checkterm Rio_readlineb(rp, buf, MAXLINE); printf("%s", buf); } return; } //解析输入的网址 int parse_uri(char *uri, char *filename, char *cgiargs) { char *ptr; if (!strstr(uri, "cgi-bin")) { /* Static content */ //line:netp:parseuri:isstatic strcpy(cgiargs, ""); //line:netp:parseuri:clearcgi strcpy(filename, "."); //line:netp:parseuri:beginconvert1 strcat(filename, uri); //line:netp:parseuri:endconvert1 if (uri[strlen(uri)-1] == '/') //line:netp:parseuri:slashcheck strcat(filename, "home.html"); //line:netp:parseuri:appenddefault return 1; } else { /* Dynamic content */ //line:netp:parseuri:isdynamic ptr = index(uri, '?'); //line:netp:parseuri:beginextract if (ptr) { strcpy(cgiargs, ptr+1); *ptr = '\0'; } else strcpy(cgiargs, ""); //line:netp:parseuri:endextract strcpy(filename, "."); //line:netp:parseuri:beginconvert2 strcat(filename, uri); //line:netp:parseuri:endconvert2 return 0; } } //返回请求文件类型 void get_filetype(char *filename, char *filetype) { if (strstr(filename, ".html")) strcpy(filetype, "text/html"); else if (strstr(filename, ".gif")) strcpy(filetype, "image/gif"); else if (strstr(filename, ".jpg")) strcpy(filetype, "image/jpeg"); else strcpy(filetype, "text/plain"); } void serve_static(int fd, char *filename, int filesize) { int srcfd; char *srcp, filetype[MAXLINE], buf[MAXBUF]; /* Send response headers to client */ get_filetype(filename, filetype); //line:netp:servestatic:getfiletype sprintf(buf, "HTTP/1.0 200 OK\r\n"); //line:netp:servestatic:beginserve sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); sprintf(buf, "%sContent-length: %d\r\n", buf, filesize); sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype); Rio_writen(fd, buf, strlen(buf)); //line:netp:servestatic:endserve /* Send response body to client */ srcfd = Open(filename, O_RDONLY, 0); //line:netp:servestatic:open srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);//line:netp:servestatic:mmap Close(srcfd); //line:netp:servestatic:close Rio_writen(fd, srcp, filesize); //line:netp:servestatic:write Munmap(srcp, filesize); //line:netp:servestatic:munmap } void serve_dynamic(int fd, char *filename, char *cgiargs) { char buf[MAXLINE], *emptylist[] = { NULL }; /* Return first part of HTTP response */ sprintf(buf, "HTTP/1.0 200 OK\r\n"); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Server: Tiny Web Server\r\n"); Rio_writen(fd, buf, strlen(buf)); if (Fork() == 0) { /* child */ //line:netp:servedynamic:fork /* Real server would set all CGI vars here */ setenv("QUERY_STRING", cgiargs, 1); //line:netp:servedynamic:setenv Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ //line:netp:servedynamic:dup2 Execve(filename, emptylist, environ); /* Run CGI program */ //line:netp:servedynamic:execve } Wait(NULL); /* Parent waits for and reaps child */ //line:netp:servedynamic:wait } void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg) { char buf[MAXLINE], body[MAXBUF]; /* Build the HTTP response body */ sprintf(body, "<html><title>Tiny Error</title>"); sprintf(body, "%s<body bgcolor=""ffffff"">\r\n", body); sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg); sprintf(body, "%s<p>%s: %s\r\n", body, longmsg, cause); sprintf(body, "%s<hr><em>The Tiny Web server</em>\r\n", body); /* Print the HTTP response */ sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-type: text/html\r\n"); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body)); Rio_writen(fd, buf, strlen(buf)); Rio_writen(fd, body, strlen(body)); } void doit(int fd) { int is_static; struct stat sbuf; char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; char filename[MAXLINE], cgiargs[MAXLINE]; rio_t rio; /* Read request line and headers */ Rio_readinitb(&rio, fd); Rio_readlineb(&rio, buf, MAXLINE); //line:netp:doit:readrequest sscanf(buf, "%s %s %s", method, uri, version); //line:HTTP请求 形式:<method><uri><version> if (strcasecmp(method, "GET")) { //line:netp:doit:beginrequesterr clienterror(fd, method, "501", "Not Implemented", "Tiny does not implement this method"); return; } //line:netp:doit:endrequesterr read_requesthdrs(&rio); //line:netp:doit:readrequesthdrs /* Parse URI from GET request */ is_static = parse_uri(uri, filename, cgiargs); //line:netp:doit:staticcheck if (stat(filename, &sbuf) < 0) { //line:netp:doit:beginnotfound clienterror(fd, filename, "404", "Not found", "Tiny couldn't find this file"); return; } //line:netp:doit:endnotfound if (is_static) { /* Serve static content */ if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) { //line:netp:doit:readable clienterror(fd, filename, "403", "Forbidden", "Tiny couldn't read the file"); return; } serve_static(fd, filename, sbuf.st_size); //line:netp:doit:servestatic } else { /* Serve dynamic content */ if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) { //line:netp:doit:executable clienterror(fd, filename, "403", "Forbidden", "Tiny couldn't run the CGI program"); return; } serve_dynamic(fd, filename, cgiargs); //line:netp:doit:servedynamic } } int main(int argc, char **argv) { /* char filetype[MAXLINE]; char filename[MAXLINE]; char cgiargs[MAXLINE]; int request_type; char url[MAXLINE]="http://km.com:80/cgi-bin/adder?34&54"; request_type=parse_uri(url,filename,cgiargs); fprintf(stdout,"%d\n",request_type); fprintf(stdout,"%s\n",filename); fprintf(stdout,"%s\n",cgiargs); get_filetype("http://km.com:80/index.html",filetype); fprintf(stdout,"%s\n",filetype); serve_static(1, "km.html", 5); clienterror(STDOUT_FILENO, "except GET", "501", "Not Implemented", "Tiny does not implement this method"); */ int listenfd, connfd, port, clientlen; struct sockaddr_in clientaddr; /* Check command line args */ if (argc != 2) { fprintf(stderr, "usage: %s <port>\n", argv[0]); exit(1); } port = atoi(argv[1]); listenfd = Open_listenfd(port); while (1) { clientlen = sizeof(clientaddr); //返回一个已连接描述符 connfd = Accept(listenfd, (struct sockaddr*)&clientaddr, &clientlen); //line:netp:tiny:accept doit(connfd); //line:netp:tiny:doit Close(connfd); //line:netp:tiny:close } return 0; }
发表评论
-
虚拟存储器
2010-06-02 10:13 10211,虚拟存储器是硬件异 ... -
关于echo服务端和客户端
2010-05-23 11:22 83811,实现的基本功能: 客户端:发送一行文本给服务器,服务器显示 ... -
异常控制流
2010-05-18 12:17 2003异常控制流(ECF) 1,这 ... -
关于链接
2010-05-17 11:35 8711,加载器创建了存储器映像,将可执行文件的相关内容拷贝到了代码 ... -
内核对文件的管理
2010-05-15 13:48 9151,文件元数据。 stat结构体: struct stat ... -
返回一段程序经过的CPU周期数
2010-05-10 10:44 9961,实例代码: #include <stdio.h& ...
相关推荐
Linux下的TinyWeb服务器是一款轻量级的Web服务器,主要用于教学和学习目的,特别是与《计算机系统:概念与编程》(Computer Systems: A Programmer's Perspective,简称CSAPP)这本书的实践部分相结合。TinyWeb的设计...
【TinyWebServer-raw_version_RAW_轻量级web服务器_TinyWebServer】是一个专为网络新手设计的项目,旨在帮助用户理解并实现一个基础的、轻量级的Web服务器。这个项目采用Linux作为开发环境,因此它基于Unix-like系统...
【Tiny-WebServer-master——纯C语言实现的微型Web服务器详解】 在当今互联网技术日新月异的时代,Web服务器作为互联网应用的基础,扮演着至关重要的角色。本文将深入探讨一个名为"Tiny-WebServer-master"的微型Web...
1. **run_web_server.exe** - 这应该是TinyWeb服务器的可执行文件,用于启动Web服务器服务。 2. **tiny.exe** - 可能是一个辅助或配置工具,用于配置或管理TinyWeb服务器。 3. **run_web_server.ini** - 这是服务器...
TinyWeb是一个基于C#语言开发的简易Web服务器项目,它为初学者提供了了解网络编程、HTTP协议以及如何在C#环境中构建服务器端应用的基础。在这个压缩包“TinyWeb.zip”中,包含的主要内容很可能是源代码文件,让我们...
1.The Tiny Web server (tiny.tar). 2.Expands with tar xvf tiny.tar into a directory called ./tiny that contains everything you need to test the Tiny web server, including sample HTML files, GIFS, CGI ...
【Tiny_web_server(小型web服务器代码)】是一个使用C语言编写的简单Web服务器,它以多线程的方式运行,能够处理HTTP请求。该服务器的实现是基于《计算机系统概论》(Computer Systems: A Programmer's Perspective,...
ArchLinux下轻量级c++服务器,根据Tinywebserver和《Linux高性能服务器编程》中的HTTP服务器升级而来.zipArchLinux下轻量级c++服务器,根据Tinywebserver和《Linux高性能服务器编程》中的HTTP服务器升级而来....
TinyWebServer是一款基于C++开发的轻量级Web服务器,主要设计用于Linux操作系统。它具有简单、高效的特点,适用于学习Web服务器的工作原理以及进行小型项目的本地开发。在深入讲解TinyWebServer之前,我们先来了解...
在这个项目中,我们将聚焦于其中的一个实践环节——构建并运行一个微型Web服务器:Tinyweb。这个过程不仅帮助我们理解HTTP协议的工作原理,还能让我们深入学习操作系统与网络编程的细节。 Tinyweb是一个小型的、...
一个java实现的webserver 支持jpg,jpeg,bmp,png,gif,bmp,css,js,html。支持404 采用xml配置文件 支持自定义文档路径 服务器端口,实现简单的虚拟主机。全手工打造 亲测运行正常。
【tiny6410 Web控制LED】是一种通过网络接口实现对硬件设备——LED灯的远程控制技术,这里主要介绍如何在友善的tiny6410开发板上搭建一个基于BOA Web服务器来实现这一功能。 首先,我们需要下载并安装BOA(简化的...
【tinyWebServer】是一个个人实现的Web服务器项目,灵感来源于经典的计算机科学教材《深入理解计算机系统》。这个项目旨在帮助开发者深入理解网络通信、HTTP协议以及服务器端编程的基本原理。通过构建自己的Web...
《深入理解计算机系统》这本书是计算机科学的经典之作,它涵盖了从硬件到软件的全面知识,其中涉及的一个小项目就是创建一个简单的Web服务器——tiny。在Windows环境下,这个项目被移植成了WinTiny,一个超小型的Web...
【标题】"WebServer:在C++ 11中实现的TinyWebServer"涉及的核心知识点是网络编程,尤其是使用C++ 11标准构建一个小型的Web服务器。C++ 11是C++语言的一个重要版本,引入了大量新特性,如自动类型推导、lambda表达式...
系统通过TCP/IP协议进行数据传输,可能使用HTTP、RTSP或Websocket等协议,确保视频流能稳定地从嵌入式设备传送到Web服务器,然后分发给远程用户。 5. **Web技术**:在客户端,用户通过Web浏览器访问监控画面。这...
Tiny Web Server 是一个针对初学者设计的轻量级Web服务器,它的核心设计理念是易用、快速以及简单配置。这个项目对于那些希望了解Web服务器工作原理或者进行基础网络编程实践的用户来说,是一个理想的学习工具。 ##...
在计算机科学中,Web开发是不可或缺的一部分,而TinyWeb项目则提供了一个深入了解Web服务器工作原理的绝佳平台。TinyWeb是一个用C语言编写的轻量级Web服务器,它简化了Web服务的核心功能,让我们能够深入学习HTTP...
tinywebTinyweb, a tiny web server based on libuv, by liigo, 2013/06.Tinyweb 是我用libuv开发的一个最精简的Web server服务器。分为三个版本,都是从真实项目中剥离出来的,从 v1 到 v2 到 v3,就是一个Web ...
TinyWebServer =============== Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器. * 使用 **线程池 + 非阻塞socket + epoll(ET和LT均实现) + 事件处理(Reactor和模拟Proactor均实现...