《TCP/IP网络编程》中多线程HTTP服务器实现代码,线程池改编

2024-03-12 14:52

本文主要是介绍《TCP/IP网络编程》中多线程HTTP服务器实现代码,线程池改编,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 最初代码
  • 线程池代码
    • locker.h
    • threadpool.h
    • task.h
    • main.cpp
    • index.html
    • 编译
  • 执行结果

最初代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>#define BUF_SIZE 1024
#define SMALL_BUF 100void* request_handler(void* arg);
void send_data(FILE *fp, char *ct, char *file_name);
const char* content_type(char *file);
void send_error(FILE *fp);
void error_handling(const char* message);int main(int argc, char *argv[])
{if(argc!=2){printf("Usage: %s <port>\n", argv[0]);exit(1);}int serv_sock = socket(PF_INET, SOCK_STREAM, 0);int option = 1;int optlen = sizeof(option);setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&option, optlen );struct sockaddr_in serv_adr;memset(&serv_adr,0 ,sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);	//本机IPserv_adr.sin_port = htons(atoi(argv[1]));	//本机端口if(bind(serv_sock,(struct sockaddr*)&serv_adr, sizeof(serv_adr) )== -1 ){error_handling("bind() error");}if(listen(serv_sock, 20) == -1 ){error_handling("listen() error");}while(1){struct sockaddr_in clnt_adr;socklen_t clnt_adr_size = sizeof(clnt_adr);int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_size );printf("Connected Request: %s:%d\n", inet_ntoa(clnt_adr.sin_addr), ntohs(clnt_adr.sin_port) );pthread_t t_id;pthread_create(&t_id, NULL, request_handler, &clnt_sock);	pthread_detach(t_id);}close(serv_sock);return 0;
}void* request_handler(void *arg)
{int clnt_sock =  *((int*)arg);char req_line[SMALL_BUF];FILE *clnt_read, *clnt_write;clnt_read = fdopen(clnt_sock, "r");		//读缓存clnt_write = fdopen( dup(clnt_sock), "w");	//写缓存fgets(req_line, SMALL_BUF, clnt_read);	//读数据(浏览器发数据给客户端)printf("req_line:%s\n",req_line);if(strstr(req_line,"HTTP/")==NULL  )	//不是HTTP协议{send_error(clnt_write);fclose(clnt_read);fclose(clnt_write);return NULL;}char method[10],file_name[30],ct[15];strcpy( method, strtok(req_line, " /")  );strcpy( file_name, strtok(NULL, " /") );strcpy( ct, content_type(file_name));if(strcmp(method, "GET") !=0)	//不是GET方法{send_error(clnt_write);fclose(clnt_read);fclose(clnt_write);return NULL;}fclose(clnt_read);send_data(clnt_write, ct, file_name);return NULL;
}void send_data(FILE *fp, char *ct, char *file_name)
{char protocol[] = "HTTP/1.0 200 OK\r\n";char server[] = "Server:Linux Web Server \r\n"; char cnt_len[] = "Content-length:2048\r\n";char cnt_type[SMALL_BUF];char buf[BUF_SIZE];sprintf(cnt_type, "Content-type:%s\r\n\r\n",ct);FILE* send_file = fopen(file_name, "r");if(send_file == NULL){send_error(fp);fclose(fp);return;}fputs(protocol, fp);fputs(server, fp);	fputs(cnt_len, fp);fputs(cnt_type, fp);while(fgets(buf,BUF_SIZE,send_file)!=NULL){fputs(buf, fp);fflush(fp);}fflush(fp);fclose(fp);
}const char* content_type(char *file)
{char extension[SMALL_BUF];char file_name[SMALL_BUF];strcpy(file_name, file);strtok(file_name,".");strcpy(extension, strtok(NULL,".") );if(!strcmp(extension, "html")||!strcmp(extension,"htm") ){return "text/html";}else{return "text/plain";}
}	void send_error(FILE *fp)
{char protocol[] = "HTTP/1.0 400 Bad Request\r\n";	//状态行char server[] = "Server:Linux Web Server\r\n";		//消息头char cnt_len[] = "Content-length:2048\r\n";char cnt_type[] = "Content-type:text/html\r\n\r\n";	//空行char content[] = "<html><head><title>NETWORK </title> </head>""<body> <font size=+5> <br>404 Error!  </font>   </body>  </html>";fputs(protocol, fp);fputs(server, fp);fputs(cnt_len, fp);fputs(cnt_type, fp);fputs(content, fp);fflush(fp);}void error_handling(const char *message)
{fputs(message, stderr);fputc('\n',stderr);exit(1);
}

线程池代码

locker.h

#ifndef LOCKER_H
#define LOCKER_H#include <exception>
#include <pthread.h>
#include <semaphore.h>/*封装信号量的类*/
class Sem
{
public:/*创建并初始化信号量*/Sem(){if( sem_init( &m_sem, 0, 0 )!=0 ){/* 构造函数没有返回值,抛出异常来报告错误*/throw std::exception();}}/*销毁信号量*/~Sem(){sem_destroy(&m_sem);}/*等待信号量*/bool wait(){return sem_wait( &m_sem ) == 0;}/*增加信号量*/bool post(){return sem_post( &m_sem ) == 0;}
private:sem_t m_sem;
};/*封装互斥锁*/
class Locker
{
public:/*创建并初始化互斥锁*/Locker(){if( pthread_mutex_init(&m_mutex, NULL) != 0 ){throw std::exception();}}/*销毁互斥锁*/~Locker(){pthread_mutex_destroy( &m_mutex );}/*获取互斥锁*/bool lock(){return pthread_mutex_lock(&m_mutex) == 0 ;}/*释放互斥锁*/bool unlock(){return pthread_mutex_unlock(&m_mutex) == 0 ;}
private:pthread_mutex_t m_mutex;
};#endif

threadpool.h

#ifndef THREADPOOL_H
#define THREADPOOL_H#include <list>
#include <cstdio>
#include <exception>
#include <pthread.h>
#include <semaphore.h>
#include "locker.h"/*线程池类, 将它定义为模板类是为了代码复用。模板参数T是任务类*/
template< typename T >
class ThreadPool
{
public:ThreadPool(int thread_number = 8, int max_requests = 10000 );~ThreadPool();/*往请求队列中添加任务*/bool append(T* request);private:/*工作线程运行的函数,它不断从工作队列中取出任务并执行之*/static void* worker(void* arg);void run();
private:int m_thread_number;	//线程池中的线程数int m_max_requests;	//请求队列中允许的最大请求数pthread_t *m_threads;	//线程描述符数组,大小为m_thread_number	std::list<T*> m_workqueue;	/*请求队列 T是任务类*/Locker m_queuelocker;	//保护请求队列的互斥锁Sem m_queuestat;	//是否有任务需要处理,唤醒bool m_stop;		//是否结束线程
};template <typename T>
ThreadPool<T>::ThreadPool(int thread_number, int max_requests):m_thread_number(thread_number),m_max_requests(max_requests),m_stop(false),m_threads(NULL){if(thread_number<=0||max_requests<=0 ) {throw std::exception();}m_threads = new pthread_t[m_thread_number];		//动态分配if(!m_threads){throw std::exception();}/*创建thread_number个线程,并将它们设置为脱离线程*/for(int i=0;i<thread_number;i++){printf("create the %dth thread\n", i);if(pthread_create(m_threads+i, NULL, worker, this ) != 0)	//线程执行worker函数(工作者),把线程池对象传入线程,执行线程的run()函数{delete[] m_threads;throw std::exception();}if( pthread_detach(m_threads[i]) ){delete[] m_threads;throw std::exception();}}
}template< typename T>
ThreadPool<T>::~ThreadPool()
{delete[] m_threads;m_stop = true;
}template< typename T>
bool ThreadPool<T>::append(T* request)
{/*操作工作队列时一定要加锁*/m_queuelocker.lock();if(m_workqueue.size() > m_max_requests )	{m_queuelocker.unlock();return false;}	m_workqueue.push_back(request);	//任务加入队列m_queuelocker.unlock();m_queuestat.post();		//wait() P, post() V	V操作唤醒run()return true;
}template< typename T>
void* ThreadPool<T>::worker(void* arg)
{ThreadPool *pool = (ThreadPool*)arg;pool->run();return pool;
}template< typename T>
void ThreadPool<T>::run()
{while(!m_stop){m_queuestat.wait();	//P操作,有请求m_queuelocker.lock();if(m_workqueue.empty() ){m_queuelocker.unlock();continue;}T* request = m_workqueue.front();m_workqueue.pop_front();m_queuelocker.unlock();if(!request){continue;}request->process();delete request;}
}#endif

task.h

#ifndef TASK_H
#define TASK_H#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>#define SMALL_BUF 100
#define BUF_SIZE 1024class Task{
public:Task(int clnt_sock):m_clnt_sock(clnt_sock){}void process();void send_data(FILE *fp, char *ct, char *file_name);const char* content_type(char *file);void send_error(FILE *fp);void error_handling(const char *message);
private:int m_clnt_sock;
};void Task::process()
{	int clnt_sock = m_clnt_sock;char req_line[SMALL_BUF];FILE *clnt_read, *clnt_write;clnt_read = fdopen(clnt_sock, "r");		//读缓存clnt_write = fdopen( dup(clnt_sock), "w");	//写缓存fgets(req_line, SMALL_BUF, clnt_read);	//读数据(浏览器发数据给客户端)printf("req_line:%s\n",req_line);if(strstr(req_line,"HTTP/")==NULL  )	//不是HTTP协议{send_error(clnt_write);fclose(clnt_read);fclose(clnt_write);return;}char method[10],file_name[30],ct[15];strcpy( method, strtok(req_line, " /")  );strcpy( file_name, strtok(NULL, " /") );strcpy( ct, content_type(file_name));if(strcmp(method, "GET") !=0)	//不是GET方法{send_error(clnt_write);fclose(clnt_read);fclose(clnt_write);return;}fclose(clnt_read);send_data(clnt_write, ct, file_name);
}void Task::send_data(FILE *fp, char *ct, char *file_name)
{char protocol[] = "HTTP/1.0 200 OK\r\n";char server[] = "Server:Linux Web Server \r\n"; char cnt_len[] = "Content-length:2048\r\n";char cnt_type[SMALL_BUF];char buf[BUF_SIZE];sprintf(cnt_type, "Content-type:%s\r\n\r\n",ct);FILE* send_file = fopen(file_name, "r");if(send_file == NULL){send_error(fp);fclose(fp);return;}fputs(protocol, fp);fputs(server, fp);	fputs(cnt_len, fp);fputs(cnt_type, fp);while(fgets(buf,BUF_SIZE,send_file)!=NULL){fputs(buf, fp);fflush(fp);}fflush(fp);fclose(fp);
}const char* Task::content_type(char *file)
{char extension[SMALL_BUF];char file_name[SMALL_BUF];strcpy(file_name, file);strtok(file_name,".");strcpy(extension, strtok(NULL,".") );if(!strcmp(extension, "html")||!strcmp(extension,"htm") ){return "text/html";}else{return "text/plain";}
}void Task::send_error(FILE *fp)
{char protocol[] = "HTTP/1.0 400 Bad Request\r\n";	//状态行char server[] = "Server:Linux Web Server\r\n";		//消息头char cnt_len[] = "Content-length:2048\r\n";char cnt_type[] = "Content-type:text/html\r\n\r\n";	//空行char content[] = "<html><head><title>NETWORK </title> </head>""<body> <font size=+5> <br>404 Error!  </font>   </body>  </html>";fputs(protocol, fp);fputs(server, fp);fputs(cnt_len, fp);fputs(cnt_type, fp);fputs(content, fp);fflush(fp);
}		void Task::error_handling(const char *message)
{fputs(message, stderr);fputc('\n',stderr);exit(1);
}#endif

main.cpp

#include "locker.h"
#include "threadpool.h"
#include "task.h"
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>#define BUF_SIZE 1024
#define SMALL_BUF 100void error_handling(const char* message)
{fputs(message, stderr);fputc('\n',stderr);exit(1);
}int main(int argc, char *argv[] )
{/*ThreadPool<Task> *pool = NULL;try{pool = new ThreadPool<Task>;}catch(...){return 1;}for(int i = 0; i<5; i++){pool->append(new Task());}	sleep(20);*/if(argc!=2){printf("Usage: %s <port>\n", argv[0]);exit(1);}int serv_sock = socket(PF_INET, SOCK_STREAM, 0);int option = 1;int optlen = sizeof(option);setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&option, optlen );struct sockaddr_in serv_adr;memset(&serv_adr,0 ,sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);	//本机IPserv_adr.sin_port = htons(atoi(argv[1]));	//本机端口if(bind(serv_sock,(struct sockaddr*)&serv_adr, sizeof(serv_adr) )== -1 ){error_handling("bind() error");}if(listen(serv_sock, 20) == -1 ){error_handling("listen() error");}ThreadPool<Task> *pool = NULL;try{pool = new ThreadPool<Task>;}catch(...){return 1;}while(1){struct sockaddr_in clnt_adr;socklen_t clnt_adr_size = sizeof(clnt_adr);int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_size );printf("Connected Request: %s:%d\n", inet_ntoa(clnt_adr.sin_addr), ntohs(clnt_adr.sin_port) );pool->append(new Task(clnt_sock));/*pthread_t t_id;pthread_create(&t_id, NULL, request_handler, &clnt_sock);	pthread_detach(t_id);*/}close(serv_sock);return 0;
}

index.html

<html>
<head><title>Network</title>  </head><body>
<font size= +5><br> net_program interesting! </font>
</body></html>

编译

g++ -g locker.h task.h threadpool.h main.cpp -o main -lpthread

执行结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这篇关于《TCP/IP网络编程》中多线程HTTP服务器实现代码,线程池改编的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/801622

相关文章

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依