TinyHttp

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:%d\n",
		   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:%d\n",
	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:%s\n",buf);
		bzero(buf,BUFSIZ);
		// sendfile(fd,connfd,NULL,);
		if(-1 == read(connfd,buf,BUFSIZ)){
			perror("read err");
			return 1;
		}
		printf("client recv:%s\n",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:%d\n",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:%d\n",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 %d\n",poll_fd[i].fd);
                printf("%d vs %d\n",poll_fd[i].revents,poll_fd[i].revents);
                close(poll_fd[i].fd);
                printf("%d vs %d\n",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:%s\n",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 OK\n";

            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 OK\n");

        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 OK\n");

        if(-1 == listen(listenfd,10)) {
            perror("listen err");
            return 1;
        }
        printf("listen OK\n");
        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 listenfd\n");
                    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);

                }
            }
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值