C语言实现自己的web服务器
一.单线程实现web服务器
1.代码:
ser.c
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<fcntl.h>
int socket_init();
int recv_request(int c);//接收请求
void send_response(int c);//应答恢复
int main()
{
int sockfd=socket_init();
if(sockfd==-1)
{
printf("socket error\n");
exit(0);
}
while(1)
{
struct sockaddr_in caddr;
int len=sizeof(caddr);
int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//阻塞---浏览器连接,返回
if(c<0)
{
continue;
}
recv_request(c);//接收请求
send_response(c);//应答恢复
close(c);
}
exit(0);
}
int recv_request(int c)//接收请求
{
char buff[1024]={0};
int n=recv(c,buff,1023,0);
if(n<0)
{
return -1;
}
printf("recv:%s",buff);
}
void send_response(int c)//应答恢复
{
char http_buff[1024]={"HTTP 1.1 200 ok\r\n"};
strcat(http_buff,"Server:http\r\n");
int fd=open("index.html",O_RDONLY);
if(fd==-1)
{
printf("open file error\n");
return;
}
int filesize=lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);
sprintf(http_buff+strlen(http_buff),"Content-Length:%d\t\n",filesize);
strcat(http_buff,"\r\n");
send(c,http_buff,strlen(http_buff),0);
char data[1024]={0};
int n=0;
while((n=read(fd,data,1024))>0)
{
send(c,data,n,0);
}
close(fd);
}
int socket_init()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
return -1;
}
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(80);
saddr.sin_addr.s_addr=inet_addr("0.0.0.0");
int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if(res==-1)
{
return -1;
}
if(listen(sockfd,5)==-1)
{
return -1;
}
return sockfd;
}
index.html
<html>
<head>
<meta charset=UTF-8>
<title>网页</title>
</head>
<body>
<h1>你好呀</h1>
</body>
</html>
2.运行结果截图:
二.多线程实现web服务器
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<pthread.h>
#define BUFF_SIZE 4096
#define PATH "home/ubuntu/lianxi/day037"
#define ER404 "404 页面找不到"
#define HEAD_SIZE 1024
struct ArgNode
{
pthread_t id;
int c;
};
int socket_init();
char *get_filename(char buff[]);
void *thread_fun(void*arg);
int http_reponse(int c,char *filename);
int main()
{
int sockfd=socket_init();
if(sockfd==-1)
{
printf("socket error\n");
exit(0);
}
while(1)
{
struct sockaddr_in caddr;
int len=sizeof(caddr);
int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//阻塞---浏览器连接,返回
if(c<0)
{
continue;
}
struct ArgNode*p=(struct ArgNode*)malloc(sizeof(struct ArgNode));
if(p==NULL)
{
close(c);
continue;
}
p->c=c;
if(pthread_create(&(p->id),NULL,thread_fun,p)!=0)
{
free(p);
close(c);
}
close(c);
}
exit(0);
}
int socket_init()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
return -1;
}
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(80);
saddr.sin_addr.s_addr=inet_addr("0.0.0.0");
int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if(res==-1)
{
return -1;
}
if(listen(sockfd,5)==-1)
{
return -1;
}
return sockfd;
}
char *get_filename(char buff[])
{
if(buff==NULL)
{
return NULL;
}
char *ptr=NULL;
char *s=strtok_r(buff," ",&ptr);
if(s==NULL)
{
return NULL;
}
printf("请求方法:%s\n",s);
s=strtok_r(NULL," ",&ptr);
if(s==NULL)
{
return NULL;
}
if(strcmp(s,"/")==0)
{
return "/index.html";
}
return s;
}
void *thread_fun(void *arg)
{
struct ArgNode*p=(struct ArgNode*)arg;
if(p==NULL)
{
pthread_exit(NULL);//退出线程,进程其他线程可以继续执行
}
int c=p->c;
printf("c=%d\n",c);
while(1)
{
char buff[BUFF_SIZE]={0};
int n=recv(c,buff,BUFF_SIZE-1,0);//接受浏览器的HTTP请求报文
if(n<=0)
{
printf("连接关闭 读取错误:%d\n",n);
break;//浏览器关闭连接
}
printf("%s\n",buff);
char *filename=get_filename(buff);
if(filename==NULL)
{
continue;
}
printf("请求资源名: %s\n",filename);
http_reponse(c,filename);
if(http_reponse(c,filename)==-1)//生成应答报文
{
break;
}
}
close(c);
free(p);//释放堆区空间
pthread_exit(NULL);
}
int http_reponse(int c,char *filename)
{
if(filename==NULL)
{
return -1;
}
char path[256]={PATH};
strcat(path,filename);
printf("path:%s\n",path);
int fd=open(path,O_RDONLY);
if(fd==-1)
{
send(c,ER404,strlen(ER404),0);
return -1;
}
int filesize=lseek(fd,0,SEEK_END);
if(filesize<=0)//空文件或者出错
{
return -1;
close(fd);
}
lseek(fd,0,SEEK_SET);
char http_head[HEAD_SIZE]={0};
strcat(http_head,"HTTP\1.1 200 OK\r\n");
strcat(http_head,"Server: myhttp\r\n");
sprintf(http_head+strlen(http_head),"Content-Length:%d\r\n",filesize);
strcat(http_head,"\r\n");//http报头组装完成
send(c,http_head,strlen(http_head),0);//发送http报头
int num=0;
char data[BUFF_SIZE]={0};
while((num=read(fd,data,BUFF_SIZE))>0)
{
send(c,data,num,0);
}
close(fd);
return -1;
}