Linux多段发送函数,Linux使用epoll控制多个socket发送http请求

在客户端使用epoll控制多个socket发送数据,与在服务器上是类似的,也是把一个连续的同步过程拆成多个非阻塞的阶段,在一个线程内实现高并发,而不是开多个线程。

客户端使用多个socket异步高并发,一般是对服务器做压力测试的代码。

6519945178fac66feb6c77ef487523fc.png

如上图,把处理过程拆分为5个阶段:开始START,连接中CONNECTING,连接完成CONNECTED,发送完成HTTP_SENT,关闭CLOSE。

拆分开之后就需要一个上下文来记录状态和缓冲区信息,并且定义一个处理函数handler来根据不同的状态进行处理,见图中的client_t结构体。

按照代码从上到下的顺序,先说一下各个阶段的处理函数。

1,下图的client_connect()函数在START状态时调用,与服务器异步建立连接。

connect之后把写事件EPOLLOUT加入epoll描述符监控,然后把状态更新为CONNECTING连接中。

498d0597b11fd2f2adc192b4e963a9b4.png

2,状态为CONNECTING时,调用client_connect_check()函数。

它判断是否为写事件,如果是则用getsockopt()读取错误码,然后填充http请求的缓冲区。

48e69ff3e6477b399fd8332b46d6299f.png

最后,设置状态为连接完成CONNECTED,继续监控写事件EPOLLOUT,等待发送数据。

一个文件描述符fd在第一次加入epoll时用EPOLL_CTL_ADD,第二次用EPOLL_CTL_MOD修改要监控的事件。

因为接下来要发送http请求,这里还是EPOLLOUT事件。

63329b66f51fa83a4feb907c2539aa13.png

3,client_http_send()为发送函数,在socket可写时一直写数据,直到把缓冲区的http请求数据写完,然后监控socket的读事件EPOLLIN,等待服务器的响应。

如果被打断,errno为EINTR,继续写。

如果不可写,errno为EAGAIN,则退出等待下次可写事件。

写完之后,用epoll_ctl()函数把对应的事件改为EPOLLIN,参数依然是EPOLL_CTL_MOD。

client的状态变为HTTP_SENT。

c4e425540c0c7d2bcb1a975a24fc06a3.png

4,在可读的时候,使用recv读数据,并记录读到的字节数。

这里我们没有做http解析,所以不知道数据什么时候读完。

recv()有可能返回0,这时socket里没数据可读,break。

6b8e3049e58874b1395d46484e1e77fd.png

5,client_close()函数,我们在CLOSE状态或者出错时调用,关闭socket,从新连接。

首先把socket的fd从epoll监控中删除,这里用EPOLL_CTL_DEL参数,并且epoll_event的指针为NULL。

然后关闭socket的fd,并把它设为-1,免得误用。

释放http请求数据的写缓冲区,把状态再次设置为START,再次开始。

3d958a9e0fa8c32f076157bf314985d9.png

下图为client_handler()函数,它会根据状态调用不同的函数处理,通过一个switch case语句。

如果出错则把状态设置为CLOSE。

如果发送完http请求了,则在3秒后把状态设置为CLOSE(默认3秒内读完了响应,读不完也没事)。

设置为CLOSE之后,连接会关闭,并再次开始。

a47e9a2e4fc2b9918acb9806510a6a6f.png

client_handler实际管理了一个client的状态机,让客户端不断的重复与服务器的http请求过程。

最后是main函数,屏蔽了SIGPIPE信号,然后创建epfd。

初始化client数组,状态设置为START,fd为-1,记录时间。

227956edcc79ac7114bf3cb497c78730.png

之后是一个while循环,使用epoll_wait监控,500毫秒超时。

client_t的指针在往epfd里添加事件时加在epoll_event的data.ptr这里。

把ev->events复制给c->events 是为了在handler里对比是写事件还是读事件。

02f18268ab345195fd123babd3399f2e.png

第二个for循环相当于处理定时器,这里没做定时器的管理结构,只是在handler里比较了当前时间和client记录的上次时间,固定为3秒。

我们把N_CLIENT的数字通过main函数的命令行参数传过来,就可以灵活选择客户端的数量了。

最后两张是运行结果图。

7f3c015d301b5f9cb72790222eff2bb3.png

cfe8c1e4ef4914b2cc9c9f2a3e7a77ea.png

举报/反馈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值