最初代码
#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 100
void* 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); //本机IP
serv_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 1024
class 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 100
void 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); //本机IP
serv_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
执行结果