用epoll实现http/https客户端

主要流程:

如果处理简单的客户端请求单线程即可处理,此方法较为简单不做阐述。如果需要处理复杂的工作逻辑或者需要模拟机器人请求大量的服务器,需要两个线程,一个任务线程,一个工作线程,可达到每秒平均处理数千的并发量。

任务线程:

从任务队列获取任务,创建socket并设置非阻塞,将该socket加入epoll句柄,connect目标服务器。

sockfd = socket(AF_INET, SOCK_STREAM, 0);

fcntl(sockfd, F_SETFL,  fcntl (socket_fd, F_GETFL,0) | O_NONBLOCK);

struct epoll_event ev;

ev.events = EPOLLIN | EPOLLOUT | EPOLLET;

ev.data.ptr = my_ev;(my_ev保存了后续处理的所有数据);

epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);

connect(sockfd,(struct sockaddr*)&my_ev->dest,sizeof(sockaddr_in))(无需判断connect返回值,后续会在epoll事件中触发);

工作线程:

等待epoll事件触发,如果返回(EPOLLHUP | EPOLLERR),则证明连接出错(目标ip不存在,目标端口不在监听状态等原因)。如果返回EPOLLOUT,则证明连接成功,可以进行写操作。如果返回EPOLLIN | EPOLLOUT,则证明可读可写,这时候就需要按照自定义的数据来判断了,如过接收完成则进行处理后续工作逻辑。无论事件成功或者失败处理完之后均要做后续清理工作。

epoll_wait(epfd,events,YOUR_SIZE,-1);

error_handle()

do_write()

do_read()

clean();

https特殊性:

http在tcp连接成功之后直接开始与对端交互,比较简单,此处省略,需要注意的是所有的收发数据均在非阻塞模式下进行,关于非阻塞socket的使用可以参考另一篇文章非阻塞socket使用。此文所使用的https库为openssl,tcp建立连接成功后进行ssl连接,连接时间可能较长,由于全部使用非阻塞,所以ssl连接是否成功需要事件返回后多次判断。

连接准备工作(ev为自定义数据的指针)

ev->ctx = SSL_CTX_new(SSLv23_client_method());

ev->ssl = SSL_new(ev->ctx);

SSL_set_mode(ev->ssl,SSL_MODE_ENABLE_PARTIAL_WRITE);

SSL_set_fd(ev->ssl,ev->sockfd);

ssl连接(需要多次判断)

int ssl_conn_ret = SSL_connect(ev->ssl);

if (1 == ssl_conn_ret)

{

// ssl连接成功,开始和对端交互

}

//连接失败,根据错误码判断是需要更多时间来完成连接还是连接失败。

int ssl_conn_err = SSL_get_error(ev->ssl,ssl_conn_ret);

if (SSL_ERROR_WANT_WRITE == ssl_conn_err||SSL_ERROR_WANT_READ == ssl_conn_err)

{

// 需要更多时间来完成ssl连接

}

else

{

//连接失,做清理工作

}

ssl读写判断

while((rtn = SSL_write(ev->ssl,ev->send_buf,ev->send_len)) <= 0)

{

        int ssl_conn_err = SSL_get_error(ev->ssl,rtn);

        if (SSL_ERROR_WANT_WRITE == ssl_conn_err && rtn != 0)

        {

                continue;

        }

        // 写失败

        return -1;

}

返回值判断

rtn = send_len:发送成功

rtn < send_len:发送失败

do

{

        rtn = SSL_read(ev->ssl,recv_buf+size,1024);

        if(rtn < 0)

        {

                int ssl_conn_err = SSL_get_error(ev->ssl,rtn);

                if (SSL_ERROR_WANT_READ == ssl_conn_err)

                {

                        continue;

                }

                //读失败

                free(recv_buf);

                return -1;

        }

        size += rtn;

}

while(rtn > 0 && size < 1024*1024);

接收判断

size = 0:对端关闭

size > 0:接收成功


http读写

发送

while((size = send(ev->sockfd,ev->send_buf,ev->send_len,0)) < 0)

{

        if(errno == EINTR || errno == EAGAIN)

        {

                continue;

        }

        //失败

        return -1;

}

返回值判断

size = send_len:发送成功

size < send_len:发送失败


接收

do

{

        rtn = recv(ev->sockfd,recv_buf+size,1024,0);

        if(rtn < 0)

        {

                if((errno == EINTR || errno == EAGAIN))

                {

                        continue;

                }

                //接收失败

                free(recv_buf);

                return -1;

        }

        size += rtn;

}

while(rtn > 0 && size < 1024*1023);

接收判断

size = 0:对端关闭

size > 0:接收成功


注意:

send分为阻塞和非阻塞,阻塞模式下,如果正常的话,会直到把你所需要发送的数据发完再返回;非阻塞,会根据你的socket在底层的可用缓冲区的大小,来将你的缓冲区当中的数据拷贝过去,有多大缓冲区就拷贝多少,缓冲区满了就立即返回,这个时候的返回值,只表示拷贝到缓冲区多少数据,但是并不代表发送多少数据,此时本程序直接认为发送失败,具体原因未知,可能缓冲区满了或者内存不够什么原因,

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容