欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C/C++實現(xiàn)高并發(fā)http服務(wù)器的代碼示例

 更新時間:2023年07月14日 10:22:11   作者:Trouble..  
這篇文章簡單給大家介紹了C/C++實現(xiàn)高并發(fā)http服務(wù)器的代碼示例,文章通過代碼和圖文介紹的非常詳細,感興趣的同學(xué)可以參考閱讀

http高并發(fā)服務(wù)器實現(xiàn)

基礎(chǔ)知識

html,全稱為html markup language,超文本標記語言。

http,全稱hyper text transfer protocol,超文本傳輸協(xié)議。用于從萬維網(wǎng)(WWW:World Wide Web)服務(wù)器傳輸超文本到本地瀏覽器的傳送協(xié)議。

客戶端請求的格式:

請求方法有:GET、POST等。URL:請求地址。協(xié)議版本:HTTP的版本。

服務(wù)器響應(yīng)的格式:

-----響應(yīng)代號代號描述
服務(wù)器上存在請求的內(nèi)容,并可以響應(yīng)給客戶端200OK
客戶端的請求有異常,方法有問題501Method Not Implemented
服務(wù)器收到請求后,因為自生的問題沒法響應(yīng)500Internal Server Error
請求的內(nèi)容不存在404NOT FOUND
客戶端發(fā)送的請求格式有問題等(一般不存在)400BAD REQUEST

http服務(wù)器實現(xiàn)

文件概念

文件的Inode元信息表示文件的索引節(jié)點,存儲著文件的元信息,例如文件得創(chuàng)建者,文件創(chuàng)建日期,文件大小等。每個inode都有一個號碼,操作系統(tǒng)用inode號碼來識別不同的文件,使用命令ls -i可以查看inode號碼。

stat函數(shù)

stat是C++用于讀取文件資源管理器的庫函數(shù),頭文件為:

#include<sys/stat.h>
#include<sys/types.h>
#include<unisted.h>
int stat(const char *path,struct stat *buf);
int fstat(int fd,struct stat *buf);
int lstat(const char *path,struct stat *buf);
parameter:
	path:文件路徑
	buf:傳入的保存文件狀態(tài)的指針,用于保存文件的狀態(tài)
	fd:文件描述符
	return:成功返回0,失敗返回-1,并設(shè)置errno

stat的結(jié)構(gòu)體內(nèi)容如下所示:

struct stat {
    dev_t     st_dev;     /* ID of device containing file */
    ino_t     st_ino;     /* inode number */
    mode_t    st_mode;    /* S_ISREG(st_mode)  是一個普通文件  S_ISDIR(st_mode)  是一個目錄*/
    nlink_t   st_nlink;   /* number of hard links */
    uid_t     st_uid;     /* user ID of owner */
    gid_t     st_gid;     /* group ID of owner */
    dev_t     st_rdev;    /* device ID (if special file) */
    off_t     st_size;    /* total size, in bytes */
    blksize_t st_blksize; /* blocksize for filesystem I/O */
    blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    time_t    st_atime;   /* time of last access */
    time_t    st_mtime;   /* time of last modification */
    time_t    st_ctime;   /* time of last status change */
};

并發(fā)和并行

并發(fā)與并行的區(qū)別簡單來說所謂的并發(fā)指的是多個進程按照一定的時間間隔進行,只不過這個時間間隔很小,人類難以感受到而已,實際上在微觀角度,進程的并發(fā)執(zhí)行還是順序執(zhí)行

高并發(fā):高并發(fā)是互聯(lián)網(wǎng)分布式框架設(shè)計中必須要考慮的因素之一,通常指的是,通過設(shè)計系統(tǒng)能夠同時并行處理很多請求。

線程可以并行的執(zhí)行任務(wù)

//頭文件
#include<pthread.h>
//函數(shù)
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg);
pthread_t:當前Linux中可理解為:typedef unsigned long int pthread_t
args1:傳出參數(shù),保存系統(tǒng)為我們分配好的線程ID;
args2:通常傳NULL,表示使用線程默認屬性。若想使用具體屬性也可以修改該參數(shù)。
args3:函數(shù)指針,指向線程主函數(shù)(線程體),函數(shù)運行結(jié)束,則線程結(jié)束。
args4:線程主函數(shù)執(zhí)行期間所需要使用的函數(shù)。

在一個線程中調(diào)用pthread_create()創(chuàng)建新的線程后,當前線程從pthread_create()返回繼續(xù)往下執(zhí)行,而新的線程所執(zhí)行的代碼由我們傳給pthread_create的函數(shù)指針start_routine決定。start_routine函數(shù)接收一個參數(shù),是通過pthread_createarg參數(shù)傳遞給它的,該參數(shù)的類型為void *,這個指針按什么類型解釋由調(diào)用者自己定義。start_routine的返回值類型也是void *,這個指針的含義同樣由調(diào)用者自己定義。start_routine返回時,這個線程就退出了,其它線程可以調(diào)用pthread_join得到start_routine的返回值。
pthread_create成功返回后,新創(chuàng)建的線程的id被填寫到thread參數(shù)所指向的內(nèi)存單元。
attr參數(shù)表示線程屬性。

pthread_exit (status) 

pthread_exit用于顯式地退出一個線程。通常情況下,pthread_exit() 函數(shù)是在線程完成工作后無需繼續(xù)存在時被調(diào)用。
如果 main() 是在它所創(chuàng)建的線程之前結(jié)束,并通過 pthread_exit() 退出,那么其他線程將繼續(xù)執(zhí)行。否則,它們將在 main() 結(jié)束時自動被終止。

gcc/g++ 編譯時需要添加 -pthread進行編譯。

gcc test.c -pthread -o test

簡單的多線程實例:

#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define NUM_THREADS     5
void *PrintHello(void *threadid)
{  
   // 對傳入的參數(shù)進行強制類型轉(zhuǎn)換,由無類型指針變?yōu)檎螖?shù)指針,然后再讀取
   int tid = *((int*)threadid);
   cout << "Hello Runoob! 線程 ID, " << tid << endl;
   pthread_exit(NULL);
}
int main ()
{
   pthread_t threads[NUM_THREADS];
   int indexes[NUM_THREADS];// 用數(shù)組來保存i的值
   int rc;
   int i;
   for( i=0; i < NUM_THREADS; i++ ){      
      cout << "main() : 創(chuàng)建線程, " << i << endl;
      indexes[i] = i; //先保存i的值
      // 傳入的時候必須強制轉(zhuǎn)換為void* 類型,即無類型指針        
      rc = pthread_create(&threads[i], NULL, 
                          PrintHello, (void *)&(indexes[i]));
      if (rc){
         cout << "Error:無法創(chuàng)建線程," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

最終代碼

服務(wù)器代碼樣例:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <errno.h>
#include<pthread.h>
#define SERVER_PORT 80
void do_http_request(int client_sock);
int get_line(int client_sock, char *buf, int size);
void do_http_response(int client_sock, const char *path);
void headers(int client_sock, FILE *resource);
void cat(int client_sock, FILE *resource);
void not_found(int client_sock);
void inner_error(int client_sock);
int main(void)
{
    int sock;
    struct sockaddr_in server_addr;
    sock = socket(AF_INET, SOCK_STREAM, 0);
    // printf("wait \n");
    bzero(&server_addr, 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);
    bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
    listen(sock, 128);
    printf("wait client connect\n");
    int done = 1;
    while (done)
    {
        struct sockaddr_in client;
        int client_sock, len, i;
        char client_ip[64];
        char buf[256];
        socklen_t client_addr_len;
        client_addr_len = sizeof(client);
        client_sock = accept(sock, (struct sockaddr *)&client, &client_addr_len);
        printf("client ip: %s \t port is : %d \n", inet_ntop(AF_INET, &client.sin_addr.s_addr, client_ip, sizeof(client_ip)), ntohs(client.sin_port));
        pthread_t tid;
		int* ptr_int=NULL;
		int err=0;
		ptr_int=(int*)malloc(sizeof(int));
		*ptr_int=client_sock;
		if(err=pthread_create(&tid,NULL,do_http_request,(void*)ptr_int)){
			printf(stderr,"cannot create thread. reason: %s\n",strerror(errno));
			if(ptr_int) free(ptr_int);
		}
        // do_http_request(client_sock);
        // close(client_sock);
    }
    close(sock);
    return 0;
}
void* do_http_request(void* p_client_sock)
{
    int len = 0;
    char buf[256], method[64], url[256], path[256];
    int client_sock=*(int *)p_client_sock;
    struct stat st;
    // http response struct: request_method url protocol_version \r\n
    len = get_line(client_sock, buf, sizeof(buf));
    if (len > 0)
    {
        int i = 0, j = 0;
        while (!isspace(buf[j]) && i < sizeof(method) - 1)
        {
            method[i] = buf[j];
            i++;
            j++;
        }
        // set end tag
        method[i] = '\0';
        printf("method: %s\n", method);
        // method is GET request
        if (strncasecmp(method, "GET", i) == 0)
        {
            printf("request method is GET\n");
            while (isspace(buf[j]))
            {
                j++;
            }
            i = 0;
            while (!isspace(buf[j]) && i < sizeof(url) - 1)
            {
                url[i] = buf[j];
                i++;
                j++;
            }
            url[i] = '\0';
            if (strncasecmp(url, "/favicon.ico", i) == 0)
            {
                strcpy(url, "/hello.html");
            }
            printf("url:%s\n", url);
            // read surplus request
            do
            {
                len = get_line(client_sock, buf, sizeof(buf));
                printf("%s\n", buf);
            } while (len > 0);
            // get local url file, and process ? in url, eg. url=128.0.0.2/hel.html?wang=dedefe
            char *pos = strchr(url, '?');
            if (pos)
            {
                // \0 represent string end tag
                *pos = '\0';
                printf("real url: %s\n", url);
            }
            sprintf(path, "./html_doc%s", url);
            printf("path:%s\n", path);
            // execute http response
            // if file is exist, to response 200, ok,and send html file,else response 404 NOT FOUND
            if (stat(path, &st) == -1)
            {
                printf("--------------------");
                fprintf(stderr, "stat %s failed. reason :%s\n", strerror(errno));
                not_found(client_sock);
            }
            else
            {
                printf("*****************");
                if (S_ISDIR(st.st_mode))
                {
                    strcat(path, "/index.html");
                }
                do_http_response(client_sock, path);
            }
        }
        else
        {
            // request method is not GET,read http head, and response client request
            fprintf(stderr, "warning, other request [%s]\n", method);
            do
            {
                len = get_line(client_sock, buf, sizeof(buf));
                printf("%s\n", buf);
            } while (len > 0);
            // unimplement()
        }
    }
    else
    {
        printf("method is error");
    }
    close(client_sock);
    if(p_client_sock) free(p_client_sock);
}
void do_http_response(int client_sock, const char *path)
{
    FILE *resource = NULL;
    resource = fopen(path, "r");
    if (resource == NULL)
    {
        not_found(client_sock);
        return;
    }
    // send http head
    headers(client_sock, resource);
    // send http body
    cat(client_sock, resource);
    // printf("end response!!!!");
    fclose(resource);
}
void headers(int client_sock, FILE *resource)
{
    struct stat st;
    int fileid = 0;
    char temp[64];
    char buf[1024] = {0};
    strcpy(buf, "HTTP/1.0 200 OK\r\n");
    strcat(buf, "Server: Martin Server\r\n");
    strcat(buf, "Content-Type: text/html\r\n");
    strcat(buf, "Connection: Close\r\n");
    fileid = fileno(resource);
    /* fstat: Get file attributes for the file, device, pipe, or socket
       that file descriptor FD is open on and put them in BUF.  */
    if (fstat(fileid, &st) == -1)
    {
        inner_error(client_sock);
    }
    snprintf(temp, 64, "Content-Length:%d\r\n\r\n", st.st_size);
    strcat(buf, temp);
    printf(stdout, "header: %s", buf);
    if (send(client_sock, buf, strlen(buf), 0) < 0)
    {
        fprintf(stderr, "send fail,data %s, reason %s", buf, strerror(errno));
    }
}
void cat(int client_sock, FILE *resource)
{
    char buf[1024];
    fgets(buf, sizeof(buf), resource);
    while (!feof(resource))
    {
        int len = write(client_sock, buf, strlen(buf));
        if (len < 0)
        {
            fprintf(stderr, "send boady error. reason %s\n", strerror(errno));
            break;
        }
        fprintf(stdout, "%s", buf);
        fgets(buf, sizeof(buf), resource);
    }
}
int get_line(int client_sock, char *buf, int size)
{
    int count = 0;
    char ch = '\0';
    int len = 0;
    while (count < size - 1 && ch != '\n')
    {
        len = read(client_sock, &ch, 1);
        if (len == 1)
        {
            if (ch == '\r')
                continue;
            else if (ch == '\n')
                break;
            buf[count] = ch;
            count++;
        }
        else if (len == -1)
        {
            perror("read fail");
            count = -1;
            break;
        }
        else
        {
            fprintf(stderr, "client close.\n");
            count = -1;
            break;
        }
    }
    if (count >= 0)
        buf[count] = '\0';
    return count;
}
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 none xistent.\r\n\
</BODY>\r\n\
</HTML>";
    int len = write(client_sock, reply, strlen(reply));
    fprintf(stdout, reply);
    if (len < 0)
    {
        fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno));
    }
}
void inner_error(int client_sock)
{
    const char *reply = "HTTP/1.0 500 Internal Sever Error\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>Inner Error</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
    <P>服務(wù)器內(nèi)部出錯.\r\n\
</BODY>\r\n\
</HTML>";
    int len = write(client_sock, reply, strlen(reply));
    fprintf(stdout, reply);
    if (len <= 0)
    {
        fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno));
    }
}

客戶端代碼樣例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERVER_PORT 666
#define SERVER_IP "127.0.0.1"
int main(int argc, char *argv[])
{
    int sockfd;
    char *message;
    struct sockaddr_in servaddr;
    int n;
    char buf[64];
    if (argc != 2)
    {
        fputs("Usage: ./echo_client message \n", stderr);
        exit(1);
    }
    message = argv[1];
    printf("message: %s\n", message);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    // 重置結(jié)構(gòu)體的內(nèi)存空間
    memset(&servaddr, '\0', sizeof(struct sockaddr_in));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr);
    servaddr.sin_port = htons(SERVER_PORT);
    connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    write(sockfd, message, strlen(message));
    n = read(sockfd, buf, sizeof(buf) - 1);
    if (n > 0)
    {
        buf[n] = '\0';
        printf("receive: %s\n", buf);
    }
    else
    {
        perror("error!!!");
    }
    printf("finished.\n");
    close(sockfd);
    return 0;
}

到此這篇關(guān)于C/C++實現(xiàn)高并發(fā)http服務(wù)器的代碼示例的文章就介紹到這了,更多相關(guān)C/C++實現(xiàn)高并發(fā)http服務(wù)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺析C++中dynamic_cast和static_cast實例語法詳解

    淺析C++中dynamic_cast和static_cast實例語法詳解

    這篇文章主要介紹了淺析C++中dynamic_cast和static_cast實例演示,包括static_cast語法知識和static_cast的作用講解,namic_cast 語法詳解,需要的朋友可以參考下
    2021-07-07
  • 對比分析C語言中的gcvt()和ecvt()以及fcvt()函數(shù)

    對比分析C語言中的gcvt()和ecvt()以及fcvt()函數(shù)

    這篇文章主要介紹了對比分析C語言中的gcvt和ecvt以及fcvt函數(shù),都是將數(shù)字轉(zhuǎn)化為字符串,注意其之間的功能區(qū)別,需要的朋友可以參考下
    2015-08-08
  • 一篇文章教你用C語言模擬實現(xiàn)字符串函數(shù)

    一篇文章教你用C語言模擬實現(xiàn)字符串函數(shù)

    這篇文章主要介紹了C語言模擬實現(xiàn)字符串函數(shù),開發(fā)程序的時候經(jīng)常使用到一些字符串函數(shù),例如求字符串長度,拷貝字符串……,需要的朋友可以參考下
    2021-09-09
  • C語言實現(xiàn)圖書管理系統(tǒng)課程設(shè)計

    C語言實現(xiàn)圖書管理系統(tǒng)課程設(shè)計

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)圖書管理系統(tǒng)課程設(shè)計,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • C++設(shè)計模式之適配器模式(Adapter)

    C++設(shè)計模式之適配器模式(Adapter)

    這篇文章主要為大家詳細介紹了C++設(shè)計模式之適配器模式Adapter,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • C++實現(xiàn)LeetCode(172.求階乘末尾零的個數(shù))

    C++實現(xiàn)LeetCode(172.求階乘末尾零的個數(shù))

    這篇文章主要介紹了C++實現(xiàn)LeetCode(172.求階乘末尾零的個數(shù)),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C++簡單實現(xiàn)的全排列算法示例

    C++簡單實現(xiàn)的全排列算法示例

    這篇文章主要介紹了C++簡單實現(xiàn)的全排列算法,結(jié)合實例形式分析了C++排序操作的實現(xiàn)技巧,需要的朋友可以參考下
    2017-07-07
  • 淺談C語言轉(zhuǎn)義字符和格式控制符

    淺談C語言轉(zhuǎn)義字符和格式控制符

    下面小編就為大家?guī)硪黄獪\談C語言轉(zhuǎn)義字符和格式控制符。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • 零基礎(chǔ)詳解C語言指針進階

    零基礎(chǔ)詳解C語言指針進階

    在C語言和C++等語言中,數(shù)組元素全為指針變量的數(shù)組稱為指針數(shù)組,指針數(shù)組中的元素都必須具有相同的存儲類型、指向相同數(shù)據(jù)類型的指針變量。指針數(shù)組比較適合用來指向若干個字符串,使字符串處理更加方便、靈活
    2022-02-02
  • 簡單介紹C++中變量的引用

    簡單介紹C++中變量的引用

    這篇文章主要簡單介紹了C++中變量的引用,是C++入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09

最新評論