阻塞型mini服务器

一个以前练手的demo:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SERVER_PORT 80
#define debug 1

int get_line(int sock,char *buf,int size);
void do_http_request(int client_sock);
void do_http_response(int client_sock,int fd);
void not_found(int client_sock);


int main(void){
    
    
    int sock,ret,opt=1;
    struct sockaddr_in server_addr;
    sock = socket(AF_INET,SOCK_STREAM,0);
    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    server_addr.sin_port=htons(SERVER_PORT);
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
    ret =bind(sock,(struct sockaddr*)&server_addr,sizeof(server_addr));
    if(ret==-1){
    
    
       perror("bind is error.\n");
    }
    ret =listen(sock,5);
    if(ret==-1){
    
    
        perror("listen is error.\n");
    }
    printf("等待客户端连接!\n");
    
    while (1)
    {
    
    
       struct sockaddr_in client;
       int client_sock,len;
       char buff[256],client_ip[32];
       char send_buff[256];
       /*socklen_t client_addr_len = sizeof(client);*/
       socklen_t client_addr_len = sizeof(client);
       client_sock=accept(sock,(struct sockaddr*)&client,&client_addr_len);
       printf("client ip:%s\tport:%d\n",inet_ntop(AF_INET,&client.sin_addr,client_ip,sizeof(client_ip)),ntohs(client.sin_port));
       //读取http请求
       do_http_request(client_sock);
       /*close(client_sock);*/
    }
    close(sock);
    return 0;
    
}

void do_http_response(int client_sock,int fd){
    
    
        char send_buff[1024*1024];
        int size = lseek(fd,0,SEEK_END);//获取文件内容大小
        lseek(fd,0,SEEK_SET);//将文件指针设置到起始位置
        const char * main_header="HTTP/1.0 200 OK\r\nServer:Wuxin Server\r\nContent-Type:test-html\r\nConnection:Close";
        //1.发送main_header
        int len = write(client_sock,main_header,strlen(main_header));
        if(debug)fprintf(stdout,"do http_response.\n");
        if(debug)fprintf(stdout,"write[%d]:%s\n",len,main_header);
        //2.生成Content-Length
        len = snprintf(send_buff,64,"Content-Length:%d.\r\n\r\n",size);
        len = write(client_sock,send_buff,len);
        if(debug)fprintf(stdout,"write[%d]:%s\n",len,send_buff);
        //3.将文件内容发送出去
         len = read(fd,send_buff,size);
         if(len>0){
    
    
             write(client_sock,send_buff,strlen(send_buff));
         }else if(len==0){
    
    
             fprintf(stdout,"close connect!\n");
         }
         else {
    
    
             fprintf(stderr,"read failed.reason:%s",strerror(errno));
         }
		close(fd); // 关闭资源文件描述符
		close(client_sock); // 关闭连接套接字
        /*if(debug)fprintf(stdout,"write[%d]:%s\n",len,send_buff);*///打印出发送的数据
}

void do_http_request(int client_sock){
    
    
    char buff[256],method[64],url[256],path[256];
    int len=0;
    //读取客服端发送的请求
    len = get_line(client_sock,buff,sizeof(buff));
    /*printf("read line:%s\n",buff);*/
    if(len>0){
    
    
        int i=0,j=0;
        while (!isspace(buff[j])&&i<sizeof(method)-1)
        {
    
    
            method[i]=buff[j];
            i++;
            j++;
        }
        method[i]='\0';
        if(debug)printf("request mthod:%s\n",method);
        if(strncasecmp(method,"GET",3)==0){
    
    //不区分大小写的字符串比较
            if(debug)printf("request = GET\n");
            while(isspace(buff[j++]));//跳过空格
            i=0;
            while (!isspace(buff[j])&&i<sizeof(url)-1)
            {
    
    
                url[i]=buff[j];
                i++;
                j++;
            }
            url[i]='\0';
            if(debug)printf("request url:%s\n",url);
            do{
    
    //读完request
                len = get_line(client_sock,buff,sizeof(buff));
                if(debug)printf("read:%s\n",buff);
            }while(len>0);
            //定位服务器中html文件  
            char * pos = strchr(url,'?');
            if(pos) {
    
    
                *pos='\0';
                printf("rear url:%s\n",url);
            }
            sprintf(path,"./html_docs/%s",url);
            if(debug)printf("path:%s\n",path);
            int fd=open(path,O_RDONLY);
            if(fd==-1){
    
    //文件不存在 出错
                    fprintf(stderr,"stat %s failed.reason:%s.\n",path,strerror(errno));
                    not_found(client_sock);
                    close(fd);
            }else{
    
    
                   do_http_response(client_sock,fd);
            }
         
        } else{
    
    //不是GET请求
            fprintf(stderr,"other request %s\n",method);
            do{
    
    //读完request 未实现响应
                len = get_line(client_sock,buff,sizeof(buff));
                if(debug)printf("read:%s\n",buff);
            }while(len>0);
        }
        
    }


}

void not_found(int client_sock){
    
    
        const char * reply ="HTTP/1.0 404 NOT FOUND\r\n\
Content-Type: text/html\r\n\
\r\n\
<HTML lang=\"zh-CN\">\r\n\
<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\r\n\
<HEAD>\r\n\
<TITLE>NOT FOUND</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
	<P>文件不存在!\r\n\
    <P>The server could not fulfill your request because the resource specified is unavailable or nonexistent.\r\n\
</BODY>\r\n\
</HTML>\n";
        int len = write(client_sock,reply,strlen(reply));
        if(debug) fprintf(stdout,reply);
        if(len<0){
    
    
            fprintf(stderr,"send reply error.reason:%s.\n",strerror(errno));
        }
}

int get_line(int sock,char *buf,int size){
    
    
    int count=0,len=0;
    char ch='\0';
    while (count<size-1&&ch!='\n')
    {
    
    
        len=read(sock,&ch,1);
        if(len==1){
    
    //读取正常
            if(ch=='\r'){
    
    //回车符
                continue;
            }else if(ch=='\n'){
    
    //换行符
               // buf[count]='0';
                break;
            }
            //正常读一个字符
            buf[count]=ch;
            count++;
        }else if(len==-1){
    
    //读出错
            perror("get line error!\n");
            count=-1;
            break;
        } else{
    
    //读取到0个字符 客户端关闭
            fprintf(stderr,"client close!\n");
            count=-1;
            break;
        }
    }
    if(count>=0)buf[count]='\0';
    return count;
}
运行截图如下:

在这里插入图片描述
在这里插入图片描述
网站页面为直接复制的html.
包含解析http头部.返回资源请求等功能.

猜你喜欢

转载自blog.csdn.net/qq_43507406/article/details/115252867