Http同步/异步请求

 

Http同步/异步模式

同步异步:

某业务需要甲乙甚至多方合作的时候,

1. 总是按照“甲方请求一次,乙方应答一次”这样的有序序列处理业务,只有当“一次请求一次应答”的过程结束才可以发生下一次的“一次请求一次应答”,那么就说他们采用的是同步。(同步IO中对同一个描述符的操作必须是有序的

2. 如果甲方只要有需要,就会发送请求,不管上次请求有没有得到乙方应答。而乙方只要甲方有请求就会接受,不是等这次请求处理完毕再接受甲方新请求。这样请求应答分开的序列,就可以认为是异步。异步情况下,请求和应答不需要一致进行,可能甲方后请求的业务,却先得到乙方的应答。同步是线性的,而异步可以认为是并发的。(异步IO中,异步IO可以允许多方同时对同一个描述符发送IO请求,或者一次发多个请求,当然有机制保证如何区分这些请求,

3. 同步异步的不同在于,针对同一个描述符上的IO操作,从IO操作发起 得到 IO结果 这个过程而言,总是按照“发起请求,得到结果”这个有序序列进行的,这样便有了最小的等待这种情况:读取时,确知IO有数据,但需要等待内核拷贝数据到进程空间。这个最小情况的等待,同步IO都有。

 

异步四元组:

struct async_context *http_async_client_init(void);

 

int http_async_client_uninit(struct async_context *ctx);

 

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

 

static void *http_async_client_callback(void *arg);

 

初始化:

http_async_client_init(){
	epoll_create();
	pthread_create();
}

 

每一次http请求数据:

http_async_client_commit(){

       socket()

       connect

       send();

       epoll_ctl();

}

 

异步方式回调函数接受信息:

http_async_client_callback(){

       while(1){

       epoll_wait();

       recv();

      

       //do……

      

       epoll_ctrl();

}

}

demo: 

#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>



#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



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 sockfd = socket(AF_INET, SOCK_STREAM, 0);



       struct sockaddr_in sin = {0};

       sin.sin_addr.s_addr = inet_addr(ip);

       sin.sin_port = htons(80);

       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\n\

Host: %s\r\n\

%s\r\n\

\r\n",

               resource, HTTP_VERSION,

               hostname,

               CONNECTION_TYPE

               );



       send(sockfd, buffer, strlen(buffer), 0);



       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, const char *resource) {

       char *ip = host_to_ip(hostname);



       int sockfd = http_create_socket(ip);



       char *content =  http_send_request(sockfd, hostname, resource);

       if (content == NULL) {

              printf("have no data\n");

       }



       puts(content);

       close(sockfd);

       free(content);

}





#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;

       char *resource;

};





int http_async_client_commit(struct async_context *ctx, const char *hostname, 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(80);

       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\n\

Host: %s\r\n\

%s\r\n\

\r\n",

               resource, HTTP_VERSION,

               hostname,

               CONNECTION_TYPE

               );



       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);



}



struct http_request reqs[] = {

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

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

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

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

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

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

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

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

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

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

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

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

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

};





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

      

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

      

}







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



#if 0

       //同步阻塞方式

       int count = sizeof(reqs) / sizeof(reqs[0]);

       int i = 0;

       for (i = 0;i < count;i ++) {

              http_client_commit(reqs[i].hostname, reqs[i].resource);

       }

      

#else



       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_async_client_commit(ctx, reqs[i].hostname, reqs[i].resource, http_async_client_result_callback);

       }





       getchar();



       http_async_client_uninit(ctx);

#endif



}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值