概述
HTTP报文结构
请求报文
//client
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
void show_info(int connfd){
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
socklen_t local_addr_len = sizeof(local_addr);
getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
printf("client local %s:%dn",
inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
struct sockaddr_in peer_addr;
bzero(&peer_addr,sizeof(peer_addr));
socklen_t peer_addr_len = sizeof(peer_addr);
getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
printf("clinet peer%s:%dn",
inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
if(3 != argc){
printf("usage:%s <ip> <#port> n",argv[0]);
return 1;
}
//建立套接字
int connfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == connfd){
perror("socket err");
return 1;
}
struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr(argv[1]);
remote_addr.sin_port = htons(atoi(argv[2]));
//连接到远方主机端口
if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
perror("connect err");
return 1;
}
show_info(connfd);
char buf[BUFSIZ];
bzero(buf,BUFSIZ);
while(fgets(buf,BUFSIZ,stdin) != NULL){
write(connfd,buf,strlen(buf)+1);
printf("client send:%sn",buf);
bzero(buf,BUFSIZ);
// sendfile(fd,connfd,NULL,);
if(-1 == read(connfd,buf,BUFSIZ)){
perror("read err");
return 1;
}
printf("client recv:%sn",buf);
}
close(connfd);
}
//server
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>
#include <string>
#include <iostream>
#include <sstream>
#include<sys/poll.h>
#include<linux/fs.h>
using namespace std;
struct func_t_arg {
struct pollfd* poll_fd;
int i;
int poll_fd_cnt;
char* work_dir;
};
class ThreadPool
{
typedef void (*func_t)(struct pollfd* poll_fd,int i,int poll_fd_cnt,const char* work_dir);
public:
ThreadPool(size_t count):destroy(false)
{
// 初始化互斥锁和条件变量
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
// 初始化线程组
for(int i=0; i<count; i++) {
pthread_t tid;
pthread_create(&tid,NULL,reinterpret_cast<void*(*)(void*)>(&ThreadPool::Route),this);
threads.push_back(tid);
}
}
~ThreadPool()
{
// 通知线程退出
destroy = true;
//让阻塞的线程不再阻塞,pthread_join是等待回收线程的。
pthread_cond_broadcast(&cond);
for(vector<pthread_t>::iterator it = threads.begin(); it != threads.end(); it++) {
pthread_join(*it,NULL);
}
// 销毁互斥锁和条件变量
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
}
void AddJob(func_t func,struct func_t_arg arg)
{
pthread_mutex_lock(&mutex);
tasks.push(func);
args.push(arg);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
private:
static void Route(ThreadPool* pPool)
{
for(;;) {
pthread_mutex_lock(&(pPool->mutex));
// 如果没有任务等待
while(pPool->tasks.empty() && !pPool->destroy) {
pthread_cond_wait(&(pPool->cond),&(pPool->mutex));
}
// 线程退出
if(pPool->destroy) {
pthread_mutex_unlock(&(pPool->mutex));
break;
}
// 获取任务
func_t task = pPool->tasks.front();
pPool->tasks.pop();
struct func_t_arg arg = pPool->args.front();
pPool->args.pop();
pthread_mutex_unlock(&(pPool->mutex));
// 执行任务
task(arg.poll_fd,arg.i,arg.poll_fd_cnt,arg.work_dir);
}
}
private:
vector<pthread_t> threads; ///< 线程组
queue<func_t> tasks; ///< 任务队列
queue<struct func_t_arg> args; ///< 参数队列
pthread_mutex_t mutex;
pthread_cond_t cond;
bool destroy; ///< 线程池销毁标志
};
//char* work_dir = NULL;
//struct pollfd poll_fd[INR_OPEN_MAX];
void show_info(int connfd)
{
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
socklen_t local_addr_len = sizeof(local_addr);
getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
printf("server local %s:%dn",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
struct sockaddr_in peer_addr;
bzero(&peer_addr,sizeof(peer_addr));
socklen_t peer_addr_len = sizeof(peer_addr);
getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
printf("server peer %s:%dn",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
void Handle(struct pollfd* poll_fd,int i,int poll_fd_cnt,const char* work_dir)
{
char buf[BUFSIZ];
for(;;) {
bzero(buf,BUFSIZ);
ssize_t len;
if((len = read(poll_fd[i].fd,buf,BUFSIZ-1)) == -1) {
perror("read err");
pthread_exit((void*)1);
}
if(0 == len) {
printf("close %dn",poll_fd[i].fd);
printf("%d vs %dn",poll_fd[i].revents,poll_fd[i].revents);
close(poll_fd[i].fd);
printf("%d vs %dn",poll_fd[i].revents,poll_fd[i].revents);
memcpy(poll_fd+i,poll_fd+i+1,poll_fd_cnt-i-1);
poll_fd_cnt--;
i--;//数组发生变化,重新判断i的fd
break;
}
printf("server recv:%sn",buf);
// 报文解析,获取URI
int url_start = 0;
int url_end = 0;
for(int j=0; j<len; j++) {
if(buf[j] == ' ') {
if(0 == url_start) {
url_start = j+1;
} else {
url_end = j;
break;
}
}
}
string url(buf+url_start,url_end-url_start);
cout << "url:" << url << endl;
string file = string(work_dir) + url;
cout << "file" << file << endl;
char* accept = strstr(buf,"Accept:");
if(NULL == accept) {
perror("No Accept");
}
char* type = accept + sizeof("Accept:");
int typeLen;
for(int j=0; j< len - (type - buf); j++) {
if(*(type+j) == ',' || *(type+j) == 'n') {
typeLen = j;
break;
}
}
int fd = open(file.c_str(),O_RDONLY);
if(-1 == fd) {
perror("open file err");
// exit(1);
}
ostringstream oss;
oss << "HTTP/1.1 200 OKn";
struct stat file_stat;
fstat(fd,&file_stat);
oss << "Content-Length:" << file_stat.st_size << endl;
oss << "Content-Type:" << string(type,typeLen) << endl << endl;
string status = oss.str();
write(poll_fd[i].fd,status.c_str(),status.size());
if(-1 == sendfile(poll_fd[i].fd,fd,NULL,file_stat.st_size)) {
perror("sendfile err");
// exit(1);
}
close(fd);
}
close(poll_fd[i].fd);
}
int main(int argc,char* argv[])
{
if(4 != argc) {
printf("usage:%s <ip> <#port> <dir>n",argv[0]);
return 1;
}
char* work_dir = NULL;
work_dir = argv[3];
int listenfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == listenfd) {
perror("listenfd open err");
return 1;
}
printf("socket create OKn");
int flag = 1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = inet_addr(argv[1]);
local_addr.sin_port = htons(atoi(argv[2]));
if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))) {
perror("bind err");
return 1;
}
printf("bind OKn");
if(-1 == listen(listenfd,10)) {
perror("listen err");
return 1;
}
printf("listen OKn");
struct pollfd poll_fd[INR_OPEN_MAX];
poll_fd[0].fd = listenfd;
poll_fd[0].events = POLLRDNORM;
size_t poll_fd_cnt = 1;
for(;;) {
if(-1 != poll(poll_fd,poll_fd_cnt,-1)) {
if(poll_fd[0].revents == POLLRDNORM) {
printf("accept listenfdn");
int connfd = accept(listenfd,NULL,NULL);
if(-1 == connfd) {
perror("accept err");
} else {
if(poll_fd_cnt+1 == INR_OPEN_MAX) {
fprintf(stderr,"connfd size over %d",INR_OPEN_MAX);
close(connfd);
} else {
poll_fd[poll_fd_cnt].fd = connfd;
poll_fd[poll_fd_cnt].events = POLLRDNORM;
poll_fd_cnt++;
}
}
}
//初始化线程池
ThreadPool pool(3);
int i;
for(i=1; i<poll_fd_cnt; i++) {
if(poll_fd[i].revents & POLLRDNORM) {
//Handle(poll_fd,i,poll_fd_cnt,work_dir);
//初始化参数结构体
struct func_t_arg arg;
arg.poll_fd = poll_fd;
arg.i=i;
arg.poll_fd_cnt=poll_fd_cnt;
arg.work_dir=work_dir;
//往线程池添加任务
pool.AddJob(Handle,arg);
}
close(listenfd);
}
}
}
}
最后
以上就是眯眯眼小刺猬为你收集整理的TinyHttp的全部内容,希望文章能够帮你解决TinyHttp所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复