1.练习 : 简单的Web服务器
1 #ifndef _HEAD_H_ 2 #define _HEAD_H_ 3 4 #include <stdio.h> 5 #include <string.h> 6 #include <stdlib.h> 7 #include <fcntl.h> 8 #include <sys/socket.h> 9 #include <arpa/inet.h> 10 #include <unistd.h> 11 12 #define MAX 1024 13 #define MAX_LISTEN 10 14 #define MAX_PATH 37 15 #define MAX_NAME 18 16 17 #define SER_IP "127.0.0.1" 18 #define SER_PORT 8000 19 #define ROOT "./www" 20 21 #define REPLY_HEAD "HTTP/1.1 200 OK\r\nContent-Type:" 22 #define TEXT "text/html" 23 //#define IMG "image/html" 24 #define IMG "jpg/html" 25 #define REPLY_END "\r\n\r\n" 26 27 void perror_exit(char *); 28 29 #endif//_HEAD_H_
1 //main.c 2 #include "head.h" 3 4 void perror_exit(char *str) 5 { 6 perror(str); 7 exit(1); 8 } 9 10 int main(int argc, char *argv[]) 11 { 12 int fd_socket = 0, opt = 1, err = 0, fd_ctl = 0, len = 0, fd_write; 13 struct sockaddr_in serve_addr; 14 char buf[MAX] = {0}; 15 char *start = NULL, *end = NULL, *type = NULL, *filename = NULL; 16 char *asgv[2] = {0}; 17 18 fd_socket = socket(AF_INET, SOCK_STREAM, 0); 19 20 bzero(&serve_addr, sizeof(serve_addr)); 21 serve_addr.sin_family = AF_INET; 22 serve_addr.sin_port = htons(SER_PORT); 23 inet_pton(AF_INET, SER_IP, &serve_addr.sin_addr.s_addr); 24 25 err = setsockopt(fd_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 26 if(-1 == err) { 27 perror_exit("setsockopt"); 28 } 29 err = bind(fd_socket, (struct sockaddr *)&serve_addr, sizeof(serve_addr)); 30 if(-1 == err) { 31 perror_exit("bind"); 32 } 33 err = listen(fd_socket, MAX_LISTEN); 34 if(-1 == err) { 35 perror_exit("listen"); 36 } 37 38 while(1) 39 { 40 char path[MAX_PATH] = {0}; 41 42 bzero(buf, sizeof(buf)); 43 len = 0; 44 //fd_ctl = accept(fd_socket, &serve_addr, sizeof(serve_addr)); 45 fd_ctl = accept(fd_socket, NULL, NULL); 46 if(-1 == fd_ctl) { 47 perror_exit("accept"); 48 } 49 len = read(fd_ctl, buf, MAX); 50 if(-1 == len) { 51 perror_exit("read"); 52 } 53 buf[len] = '\0'; 54 start = strstr(buf, " "); 55 end = strstr(start + 1, " "); 56 *end = '\0'; 57 filename = start + 2; 58 printf("filename == %s\n", filename); 59 if(0 == strlen(filename)) { 60 filename = "index.html"; 61 } 62 printf("filename == %s\n", filename); 63 sprintf(path, "%s/%s", ROOT, filename); 64 printf("path == %s\n", path); 65 err = access(path, X_OK); 66 if(0 == err) 67 { 68 pid_t pid = 0; 69 write(fd_ctl, REPLY_HEAD, strlen(REPLY_HEAD)); 70 write(fd_ctl, TEXT, strlen(TEXT)); 71 write(fd_ctl, REPLY_END, strlen(REPLY_END)); 72 73 pid = fork(); 74 if(-1 == pid) { 75 perror_exit("fork"); 76 } 77 if(0 == pid) { 78 dup2(fd_ctl, STDOUT_FILENO); 79 asgv[0] = path; 80 asgv[1] = NULL; 81 execvp(asgv[0], asgv); 82 } 83 else { 84 close(fd_ctl); 85 wait(NULL); 86 } 87 } 88 else { 89 start = rindex(filename, '.'); 90 //if((! strcmp(start, "png")) || (! strcmp(start, "jpg"))) { 91 if((! strcmp(start, "jpg"))) { 92 type = IMG; 93 } 94 else { 95 type = TEXT; 96 } 97 98 fd_write = open(path, O_RDONLY); 99 if(fd_write != -1) { 100 write(fd_ctl, REPLY_HEAD, strlen(REPLY_HEAD)); 101 write(fd_ctl, type, strlen(type)); 102 write(fd_ctl, REPLY_END, strlen(REPLY_END)); 103 104 while((len = read(fd_write, buf, MAX))) 105 { 106 write(fd_ctl, buf, len); 107 } 108 109 close(fd_write); 110 } 111 } 112 close(fd_ctl); 113 } 114 115 return 0; 116 }
2.首先运行编译好的文件
打开浏览器 , 输入127.0.0.1:8000访问服务器
3.UNIX Doamin Socket IPC
优点 :更有效率 , 不需要经过网络协议栈,不需要打包拆包,计算效验和,维护序号和应答等,只需要将应用层数据从一个进程拷贝到另一个进程。
原因 : IPC机制本质上是可靠的通讯 而网络通讯协议是为不可靠通讯设计的。
扩展:面向流,数据报,消息时都是可靠的,即不会丢失也不会顺序错乱。
是全双工的
不同点 :UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示
4,网络编程的地址是IP地址加端口号
UNIX Doamin Socket IPC 的地址是一个socket类型的文件在文件系统的路径
5.注意程序中的offsetof宏,它在stddef.h头文件中定义
#define offsetof(TYPE, MEMBER) ((int) & ((TYPE *) 0) -> MEMBER)
作用 :测量结构里面成员的偏移量
offsetof(struct sockaddr_un, sun_path)就是取sockaddr_un结构体的sun_path成员在结构体中的偏移,也就是从第几个字节开始是sun_path成员
6.注意事项 :在回头http协议中每一行的末尾都是回车加换行
HTTP头的第二行表示即将发送的文件的类型(称为)
Text/html
纯文本文件是text/plain
图片则是image/jpg, image/png