logo资料库

多线程http服务器实现流程图.pdf

第1页 / 共1页
资料共1页,全文预览结束
比较 ip 的 输入值是否为 any 是: 设置 sin_addr.s_addr = INADDR_ANY 否:设置 sin_addr.s_addr = inet_addr(ip); 1. 创建 sockaddr_in 结构体 设置关键字参数 sin_family = AF_INET sin_port = hton(port) 2. 创建套接字 int fd = socket(AF_INET, SOCK_STREAM, 0); 3. 设置端口复用 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 4. 绑定套接字 bind(fd, (struct sockaddr*)&addr, sizeof(addr)) ; 5. 监听套接字 listen(fd, 10); 6. 接收套接字 accept(listen_socket, (struct sockaddr*)&client_addr, &len); 多线程 HTTP 服务器 传入参数(ip/port) 7. 创建子线程对套接字进行处理 pthread_create(&tid, NULL, handle_client, (void*)&client_fd); void* handle_client(void* arg); accept_request(int sock); 8. 关闭套接字 close(listen_socket); pthread_detach(tid); 创建数组用来保存方法、路径 char buf[MAXSIZE] = {0}; char method[MAXSIZE/32]; char url[MAXSIZE]; char path[MAXSIZE]; 逐行读数据 get_line(int sock, char* buf, int size); MSG_PEEK 窥看外来消息。 获取方法,保存到 method 数组 while(!isspace(buf[i]) && i < strlen(buf) && j < sizeof(method) - 1){ method[j++] = buf[i++]; } method[j] = '\0'; 获取 URL, 保存到 url 数组 j = 0; while(isspace(buf[i])){ i++; } while(!isspace(buf[i]) && i < strlen(buf) && j < sizeof(url) - 1){ url[j++] = buf[i++]; } url[j] = '\0'; strcasecmp(method, "post") == 0 如果是 post 令 cgi = 1 判断方法是 get 或者是 post 如果是 get 判断是否带"?" 令 cgi = 1 如果带"?" 把"?"替换成"\0" 保存"?"后面的参数 如果不带"?" 令 cgi = 0 将 wwwRoot 拼接到 url 之前,以命令形式输出到 path sprintf(path,"wwwRoot%s",url); 如果请求的资源是 web 根目录,自动拼接上首页 if(path[strlen(path-1)] == '/'){ strcat(path, HOMEPAGE); } stat() 通过文件名 filename 获取文件信息,并保存在结构体 stat 中 请求的资源如果是目录,给每个目录下加一个缺省的首页 if(S_ISDIR(st.st_mode)){ //请求的资源如果是目录,给每个目录下加一个缺省的首页 strcat(path, HOMEPAGE); } stat(path, &st) 判断请求的资源是否具有可执行权限 S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限 S_IXGRP 00010 S_IXOTH 00001 行权限 行权限 用户组具可执 其他用户具可执 if((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH)){ cgi = 1; } 如果等于 1 exe_cgi(sock, path, method, cur_url); 比较方法是否为 get 如果为 get 将空行之前的请求报文处理完 clear_head() 如果不为 get(就是 post) 找到正文中的"Content_length: "字段,将正文长度保存起来 sprintf(line, "HTTP/1.0 200 OK\r\n"); 发送响应报文,发送之前加上报头 sprintf(line, "\r\n"); 创建两个管道,父进程需要知道子进程的执行结果,子进程需要知道参数 send(sock, line, strlen(line), 0); 判断 cgi 是否等于 1 创建父子进程 父进程负责从管道读取子进程的执行结果,并将 post 方法的参数通过管道传送给子进程 子进程将方法和参数导入环境变量,这是因为进行程序替换之后,子进程将丢失参数 子进程将管道重定向到标准输入和标准输出 以只读的方式打开请求资源 如果不等于 1 echo_www(sock, path, st.st_size); 发送响应报文 status line Content-Length 空行 请求资源 sendfile(sock, fd, NULL, size); 关闭文件
分享到:
收藏