关于c语言通过epoll同步和异步方式请求http服务器的json数据

简单总结了下http client的使用。

 

xhttp.h

 

#ifndef MEDIA_XHTTP_H
#define MEDIA_XHTTP_H

#include <pthread.h>
#define HTTP_VERSION    "HTTP/1.1"
#define USER_AGENT      "User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2\r\n"
#define ENCODE_TYPE     "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
#define CONNECTION_TYPE "Connection: close\r\n"



#define BUFFER_SIZE     4096

#define ASYNC_CLIENT_NUM        1024
#define HOSTNAME_LENGTH         128

typedef void (*async_result_cb)(const char *hostname, const char *result);


struct ep_arg {
    int sockfd;
    char hostname[HOSTNAME_LENGTH];
    async_result_cb cb;
};


struct async_context {
    int epfd;
    pthread_t thread_id;
};

struct http_request {
    char *hostname;
    int  port;
    char *resource;
};


char *host_to_ip(const char *hostname);
int  http_create_socket( char *ip,int port);
char *http_send_request(int sockfd, const char *hostname, const char *resource);
int  http_client_commit(const char *hostname, int port,const char *resource);
int  http_async_client_commit(struct async_context *ctx, const char *hostname, int port,const char *resource, async_result_cb cb);

struct async_context *http_async_client_init(void);
int http_async_client_uninit(struct async_context *ctx);

static void *http_async_client_callback(void *arg);
static void http_async_client_result_callback(const char *hostname, const char *result);


#endif

 

xhttp.c

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>       /* close */
#include <netdb.h>

#include <sys/epoll.h>
#include <pthread.h>

#include "xhttp.h"


char *host_to_ip(const char *hostname) {

    struct hostent *host_entry = gethostbyname(hostname);
    if (host_entry) {
        return inet_ntoa(*(struct in_addr*)*host_entry->h_addr_list);
    } else {
        return NULL;
    }
}

int http_create_socket( char *ip,int port) {

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in sin = {0};
    sin.sin_addr.s_addr = inet_addr(ip);
    sin.sin_port = htons(port);
    sin.sin_family = AF_INET;

    if (-1 == connect(sockfd, (struct sockaddr*)&sin, sizeof(struct sockaddr_in))) {
        return -1;
    }

    fcntl(sockfd, F_SETFL, O_NONBLOCK);

    return sockfd;

}


char *http_send_request(int sockfd, const char *hostname, const char *resource) {

    char buffer[BUFFER_SIZE] = {0};

    int len = sprintf(buffer,
                      "GET %s %s\r\nHost: %s\r\n%s\r\n\r\n",
                      resource, HTTP_VERSION,
                      hostname,
                      CONNECTION_TYPE
    );
    printf("==33333333333333333333333==\n");
    printf("request buffer:%s\n", buffer);
    send(sockfd, buffer, strlen(buffer), 0);
    printf("==44444444444444444444444==\n");

    struct timeval tv;
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    fd_set fdread;
    FD_ZERO(&fdread);
    FD_SET(sockfd, &fdread);

    char *result = malloc(sizeof(int));
    result[0] = '\0';

    while (1) {

        int selection = select(sockfd+1, &fdread, NULL, NULL, &tv);
        if (!selection || !(FD_ISSET(sockfd, &fdread))) {
            break;
        } else {
            len = recv(sockfd, buffer, BUFFER_SIZE, 0);
            if (len == 0) break;

            result = realloc(result, (strlen(result) + len + 1) * sizeof(char));
            strncat(result, buffer, len);
        }
    }

    return result;

}


int http_client_commit(const char *hostname, int port,const char *resource) {
    char *ip = host_to_ip(hostname);

    int sockfd = http_create_socket(ip,port);

    char *content =  http_send_request(sockfd, hostname, resource);
    if (content == NULL) {
        printf("have no data\n");
    }

    puts(content);
    close(sockfd);
    free(content);

    return 0;
}



int http_async_client_commit(struct async_context *ctx, const char *hostname,int port, const char *resource, async_result_cb cb) {

    char *ip = host_to_ip(hostname);
    if (ip == NULL) return -1;

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in sin = {0};
    sin.sin_addr.s_addr = inet_addr(ip);
    sin.sin_port = htons(port);
    sin.sin_family = AF_INET;

    if (-1 == connect(sockfd, (struct sockaddr*)&sin, sizeof(struct sockaddr_in))) {
        return -1;
    }

    fcntl(sockfd, F_SETFL, O_NONBLOCK);

    char buffer[BUFFER_SIZE] = {0};

    int len = sprintf(buffer,
                      "GET %s %s\r\nHost: %s\r\n%s\r\n\r\n",
                      resource, HTTP_VERSION,
                      hostname,
                      CONNECTION_TYPE
    );

    printf("request buffer:%s\n", buffer);
    int slen = send(sockfd, buffer, strlen(buffer), 0);


    struct ep_arg *eparg = (struct ep_arg*)calloc(1, sizeof(struct ep_arg));
    if (eparg == NULL) return -1;
    eparg->sockfd = sockfd;
    eparg->cb = cb;

    struct epoll_event ev;
    ev.data.ptr = eparg;
    ev.events = EPOLLIN;

    int ret = epoll_ctl(ctx->epfd, EPOLL_CTL_ADD, sockfd, &ev);

    return ret;

}

static void *http_async_client_callback(void *arg) {

    struct async_context *ctx = (struct async_context*)arg;
    int epfd = ctx->epfd;

    while (1) {

        struct epoll_event events[ASYNC_CLIENT_NUM] = {0};

        int nready = epoll_wait(epfd, events, ASYNC_CLIENT_NUM, -1);
        if (nready < 0) {
            if (errno == EINTR || errno == EAGAIN) {
                continue;
            } else {
                break;
            }
        } else if (nready == 0) {
            continue;
        }

        printf("nready:%d\n", nready);
        int i = 0;
        for (i = 0;i < nready;i ++) {

            struct ep_arg *data = (struct ep_arg*)events[i].data.ptr;
            int sockfd = data->sockfd;

            char buffer[BUFFER_SIZE] = {0};
            struct sockaddr_in addr;
            size_t addr_len = sizeof(struct sockaddr_in);
            int n = recv(sockfd, buffer, BUFFER_SIZE, 0);

            data->cb(data->hostname, buffer); //call cb

            int ret = epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL);
            //printf("epoll_ctl DEL --> sockfd:%d\n", sockfd);

            close(sockfd); /

            free(data);

        }

    }

}

struct async_context *http_async_client_init(void) {

    int epfd = epoll_create(1); //
    if (epfd < 0) return NULL;

    struct async_context *ctx = calloc(1, sizeof(struct async_context));
    if (ctx == NULL) {
        close(epfd);
        return NULL;
    }
    ctx->epfd = epfd;

    int ret = pthread_create(&ctx->thread_id, NULL, http_async_client_callback, ctx);
    if (ret) {
        perror("pthread_create");
        return NULL;
    }
    usleep(1);

    return ctx;

}

int http_async_client_uninit(struct async_context *ctx) {

    close(ctx->epfd);
    pthread_cancel(ctx->thread_id);

    return 0;
}

static void http_async_client_result_callback(const char *hostname, const char *result) {

    printf("hostname:%s, result:%s\n\n\n\n", hostname, result);

}


struct http_request reqs[] = {


   {"api.seniverse.com",80, "/v3/weather/now.json?key=0pyd8z7jouficcil&location=beijing&language=zh-Hans&unit=c" },
   {"api.seniverse.com",80, "/v3/weather/now.json?key=0pyd8z7jouficcil&location=changsha&language=zh-Hans&unit=c" },
};



int main(int argc, char *argv[]) {

    struct async_context *ctx = http_async_client_init();
    if (ctx == NULL) return -1;

    int count = sizeof(reqs) / sizeof(reqs[0]);
    int i = 0;
    for (i = 0;i < count;i ++) {

        //http_client_commit(reqs[i].hostname,reqs[i].port, reqs[i].resource);  //同步请求
        http_async_client_commit(ctx, reqs[i].hostname, reqs[i].port,reqs[i].resource, http_async_client_result_callback);//异步请求
    }

}

同步和异步,更换一个函数即可。区别就是异步有个回调函数。具体实现参考代码。输入的url,直接是url,端口和后面的网址。

后面可以进行代码,自己解析一下网址,不需要三个变量,一个完整的url解决。留点念想。可以自己动手实现一下。

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种通用的编程语言,也被广泛应用于网络编程中。开发一个HTTP服务器,可以使用C语言来实现。 HTTP服务器主要负责接收和处理HTTP请求,并返回相应的HTTP响应。在C语言中,可以使用套接字(Socket)来实现网络通信。通过创建套接字,可以监听特定的端口,以便接收客户端的HTTP请求。 对于接收到的HTTP请求服务器需要解析请求头,并根据请求内容进行相应的处理。在C语言中,可以使用字符串操作函数和正则表达式来解析请求头,提取出请求的方法,路径和参数等信息。根据具体的业务需求,服务器可以执行相应的操作,如访问数据库,处理文件等。 其中,JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于HTTP通信中传输数据。在C语言中,可以使用第三方库,如 cJSON库来处理JSON数据。 使用cJSON库,我们可以将数据转换为JSON格式,并通过HTTP响应发送给客户端。同时,我们也可以从HTTP请求中获取JSON数据并进行解析。cJSON库提供了简单易用的API,具有良好的性能和较小的内存占用。 总结来说,使用C语言开发HTTP服务器,需要利用Socket实现网络通信,并对接收的请求进行解析和处理。同时,使用JSON数据格式进行数据交换可以借助cJSON库来处理。通过这些工具和技术,我们可以开发出功能强大的C语言HTTP服务器,实现数据传输与处理的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值