网络服务器【二】多线程httpserver(pthread)

流程图

在这里插入图片描述

关键代码

void setup(pthread_attr_t * attrp)
{
    pthread_attr_init(attrp);
    // 防止僵尸线程,设置成独立线程
    pthread_attr_setdetachstate(attrp,PTHREAD_CREATE_DETACHED);
    // 初始化全局变量
    time(&server_started);
    server_requests=0;
    server_bytes_sent=0;
}
pthread_create(&worker,&attr,handle_call,fdptr);

源代码

// socklib.h
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <time.h>
#include <string.h>

#define HOSTLEN 256
#define BACKLOG 1

int make_server_socket_q(int ,int);
int make_server_socket(int portnum)
{
    return make_server_socket_q(portnum,BACKLOG);
}
int make_server_socket_q(int portnum,int backlog)
{
    struct sockaddr_in saddr;
    struct hostent* hp;
    char hostname[HOSTLEN];
    int sock_id;
    // socket()
    sock_id=socket(PF_INET,SOCK_STREAM,0);
    if(sock_id==-1)
    {
        return -1;
    }
    // init a sockaddr_in struct
    bzero(&saddr,sizeof(saddr));
    gethostname(hostname,HOSTLEN);
    printf("hostname:%s\n",hostname);
    hp=gethostbyname(hostname);
    bcopy((void*)hp->h_addr,(void*)&saddr.sin_addr,hp->h_length);
    saddr.sin_port=htons(portnum);
    saddr.sin_family=AF_INET;

    // bind()
    if(bind(sock_id,(struct sockaddr*)&saddr,sizeof(saddr))!=0)
    {
        return -1;
    }
    // listen()
    if(listen(sock_id,backlog)!=0)
    {
        return -1;
    }
    return sock_id;

}
int connect_to_server(char* host,int portnum)
{
    int sock;
    struct sockaddr_in servadd;
    struct hostent* hp;

    sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock==-1)
    {
        return -1;
    }
    bzero(&servadd,sizeof(servadd));
    hp=gethostbyname(host);
    if(hp==NULL)
    {
        return -1;
    }
    bcopy(hp->h_addr,(struct sockaddr*)&servadd.sin_addr,hp->h_length);
    servadd.sin_port=htons(portnum);
    servadd.sin_family=AF_INET;

    if(connect(sock,(struct sockaddr*)&servadd,sizeof(servadd))!=0)
    {
        return -1;
    }
    return sock;
}
// twebserv.h
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>

#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<dirent.h>
#include<time.h>

#include "socklib.h"

time_t server_started;
int server_bytes_sent;
int server_requests;
int http_reply(int fd,FILE**fpp,int code,char* msg,char* type,char* content)
{
    FILE* fp=fdopen(fd,"w");
    int bytes=0;

    if(fp!=NULL)
    {
        bytes=fprintf(fp,"HTTP/1.0 %d %s\r\n",code,msg);
        bytes+=fprintf(fp,"Content-type:%s\r\n\r\n",type);
        if(content)
        {
            bytes+=fprintf(fp,"%s\r\n",content);
        }
    }
    fflush(fp);
    if(fpp)
    {
        *fpp=fp;
    }else{
        fclose(fp);
    }
    return bytes;
}

char* file_type(char* f)
{
    char *cp;
    // 在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置
    // a.txt 返回txt
    if((cp=strrchr(f,'.'))!=NULL)
    {
        return cp+1;
    }
    return "";
}
int built_in(char* arg,int fd)
{
    FILE* fp;
    if(strcmp(arg,"status")!=0)
    {
        return 0;
    }
    http_reply(fd,&fp,200,"OK","text/plain",NULL);

    fprintf(fp,"Server started:%s",ctime(&server_started));
    fprintf(fp,"Total requests:%d\n",server_requests);
    fprintf(fp,"Bytes sent out:%d\n",server_bytes_sent);
    fclose(fp);
    return 1;
}
void setup(pthread_attr_t * attrp)
{
    pthread_attr_init(attrp);
    // 防止僵尸线程,设置成独立线程
    pthread_attr_setdetachstate(attrp,PTHREAD_CREATE_DETACHED);
    // 初始化全局变量
    time(&server_started);
    server_requests=0;
    server_bytes_sent=0;
}
void skip_rest_of_header(FILE* fp)
{
    char buf[BUFSIZ];
    while (fgets(buf,BUFSIZ,fp)!=NULL&&strcmp(buf,"\r\n")!=0);
}

void sanitize(char* str)
{
    char* src,*dest;
    src=dest=str;
    while (*src)
    {
        if(strncmp(src,"/../",4)==0)
        {
            src+=3;
        }else if(strncmp(src,"//",2)==0)
        {
            src++;
        }else{
            *dest++=*src++;
        }
    }
    *dest='\0';
    if(*str=='/')
    {
        strcpy(str,str+1);
    }
    if(str[0]=='\0'||strcmp(str,"./")==0||strcmp(str,"./..")==0)
    {
        strcpy(str,".");
    }
}
int not_exist(char* f)
{
    struct stat info;
    return(stat(f,&info)==-1);
}
void do_404(char* item,int fd)
{
    http_reply(fd,NULL,404,"Not Found","text/plain","THe item you seek is not here");
}

void cannot_do(int fd)
{
    http_reply(fd,NULL,501,"Not Implemented","text/plain","That command is not implemented");

}
int isadir(char* f)
{
    struct stat info;
    //stat() 得到文件(目录文件是一种特殊文件)属性
    return(stat(f,&info)!=-1&&S_ISDIR(info.st_mode));
}

int do_ls(char *dir,int fd)
{
    DIR* dirptr;
    struct dirent *direntp;
    FILE* fp;
    int bytes=0;
    bytes=http_reply(fd,&fp,200,"OK","text/plain",NULL);
    bytes+=fprintf(fp,"Listing of Directory %s\n",dir);

    if((dirptr=opendir(dir))!=NULL)
    {
        while(direntp=readdir(dirptr))
        {
            bytes+=fprintf(fp,"%s\n",direntp->d_name);
        }
        closedir(dirptr);
    }
    fclose(fp);
    server_bytes_sent+=bytes;
}
int ends_in_cgi(char* f)
{
    return (strcmp(file_type(f),"cgi")==0);
}

int do_cat(char* f,int fd)
{
    char* extension=file_type(f);
    char* content="text/plain";
    FILE* fpsock, *fpfile;
    int c;
    int bytes=0;
    if(strcpy(extension,"html")==0)
    {
        content="text/html";
    }else if(strcmp(extension,"gif")==0)
    {
        content="image/gif";
    }else if(strcmp(extension,"jpg")==0)
    {
        content="image/jpg";
    }else if(strcmp(extension,"jpeg")==0)
    {
        content="image/jpeg";
    }
    fpsock=fdopen(fd,"w");
    fpfile=fopen(f,"r");
    if(fpsock!=NULL&&fpfile!=NULL)
    {
        bytes=http_reply(fd,&fpsock,200,"OK",content,NULL);

        while ((c=getc(fpfile))!=EOF)
        {
            putc(c,fpsock);
            bytes++;
        }
        fclose(fpfile);
        fclose(fpsock);

    }
    server_bytes_sent+=bytes;
}
void process_rq(char *rq,int fd)
{
    char cmd[BUFSIZ],arg[BUFSIZ];
    
    // 分解request
    if(sscanf(rq,"%s%s",cmd,arg)!=2)
    {
        return;
    }
    
    sanitize(arg);
    // strcmp
    if(strcmp(cmd,"GET")!=0)
    {
        cannot_do(fd);

    }else if(built_in(arg,fd))
    {
        ;
    }
    else if(not_exist(arg))
    {
        do_404(arg,fd);

    }else if(isadir(arg))
    {
        do_ls(arg,fd);
    }else{
        do_cat(arg,fd);
    }
}


void* handle_call(void* fdptr)
{
    FILE* fpin;
    char request[BUFSIZ];
    int fd;

    fd=*(int*)fdptr;
    free(fdptr);
    fpin=fdopen(fd,"r");
    fgets(request,BUFSIZ,fpin);
    printf("got a call on %d :request = %s",fd,request);
    skip_rest_of_header(fpin);
    process_rq(request,fd);
    fclose(fpin);
}

int main(int ac,char* av[])
{
    int sock,fd;
    int* fdptr;
    pthread_t worker;
    pthread_attr_t attr;
    void* handle_call(void *);

    if(ac==1)
    {
        fprintf(stderr,"usage : tws portnum\n");
        exit(1);
    }

    sock=make_server_socket(atoi(av[1]));
    if(sock==-1)
    {
        perror("making socket");
        exit(2);
    }
    // 初始化
    setup(&attr);
    while (1)
    {
        fd=accept(sock,NULL,NULL);
        //计数
        server_requests++;
        fdptr=malloc(sizeof(int));
        *fdptr=fd;
        pthread_create(&worker,&attr,handle_call,fdptr);        
    }
    


}

图片

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
卷积是一种重要的信号处理技术,它在图像处理、语音识别、机器学习等领域得到广泛应用。计算卷积需要大量的运算,因此使用多线程可以有效提高计算效率。 pthread是一种多线程编程库,可以在C/C++中使用。下面是一个使用pthread计算卷积的示例代码: ```c++ #include <pthread.h> #define ROWS 1024 #define COLS 1024 #define KERNEL_SIZE 5 #define THREADS 4 int input[ROWS][COLS]; int output[ROWS][COLS]; int kernel[KERNEL_SIZE][KERNEL_SIZE]; void* convolve(void* arg) { int tid = *(int*)arg; int start_row = tid * ROWS / THREADS; int end_row = (tid + 1) * ROWS / THREADS; for (int i = start_row; i < end_row; i++) { for (int j = 0; j < COLS; j++) { int sum = 0; for (int k = 0; k < KERNEL_SIZE; k++) { for (int l = 0; l < KERNEL_SIZE; l++) { int x = i - KERNEL_SIZE/2 + k; int y = j - KERNEL_SIZE/2 + l; if (x >= 0 && x < ROWS && y >= 0 && y < COLS) { sum += input[x][y] * kernel[k][l]; } } } output[i][j] = sum; } } return NULL; } int main() { pthread_t threads[THREADS]; int tids[THREADS]; // initialize input and kernel // ... // create threads for (int i = 0; i < THREADS; i++) { tids[i] = i; pthread_create(&threads[i], NULL, convolve, &tids[i]); } // join threads for (int i = 0; i < THREADS; i++) { pthread_join(threads[i], NULL); } // output contains the convolved image // ... return 0; } ``` 在这个示例代码中,我们定义了一个`convolve`函数,用于计算卷积。我们创建了`THREADS`个线程,每个线程计算输入图像的一部分,并将结果存储在输出图像中。在`main`函数中,我们首先创建线程,然后等待所有线程完成任务,最后输出结果。 需要注意的是,在计算卷积时,我们需要对输入图像的边缘进行处理。在这个示例代码中,我们采用了补零的方法,即在输入图像的外围补零。另外,在计算卷积时,我们使用了一些优化技巧,如循环展开和寄存器变量,以提高计算效率。 使用pthread可以方便地实现多线程计算卷积,从而提高计算效率。但需要注意线程之间的同步和互斥,以避免竞态条件和死锁等问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值