上一篇中client用的是 发送->等待->接收 模式,如果把client也改为异步,一个进程发送完所有数据,再在epoll上监听返回的数据,能否成功呢。尝试了一下,程序如下:
client_single.cc
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFSIZE 10
#define SENDTIME 10000
#define MAXEVENTS (SENDTIME+100)
pthread_attr_t attr;
void setnonblocking(int sock)
{
int opts;
opts=fcntl(sock,F_GETFL);
if(opts<0)
{
perror("fcntl(sock,GETFL)");
exit(1);
}
opts = opts|O_NONBLOCK;
if(fcntl(sock,F_SETFL,opts)<0)
{
perror("fcntl(sock,SETFL,opts)");
exit(1);
}
}
void worker(){
char *local_addr="127.0.0.1";
int port=9988;
struct epoll_event ev, events[MAXEVENTS];
int epollfd = epoll_create(1024);
if(epollfd == -1){
perror("epoll_create");
exit(0);
}
char buf[BUFSIZE];
for(int i=0; i<SENDTIME; i++){
struct sockaddr_in serveraddr;
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1){
perror("socket");
exit(0);
}
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
inet_aton(local_addr,&(serveraddr.sin_addr));
serveraddr.sin_port=htons(port);
int ret = connect(fd, (sockaddr*)&serveraddr, sizeof(serveraddr));
if(ret<0){
perror("connect");
exit(0);
}
setnonblocking(fd);
int len = snprintf(buf, BUFSIZE, "%d", i);
ret = write(fd, buf, len);
// printf("send %s\n", buf);
if(ret != len){
printf("write error %s write_len:%d expect_len:%d\n", buf, ret, len);
perror(NULL);
exit(0);
}
ev.events = EPOLLIN;
ev.data.fd = fd;
ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
if(ret == -1){
perror("epoll_ctl");
exit(0);
}
}
int recvtime=0;
while(1){
int nfds = epoll_wait(epollfd, events, MAXEVENTS, 100);
if(nfds == -1){
perror(NULL);
}
for(int i=0; i <nfds; i++){
if(events[i].events & EPOLLIN){
int curfd = events[i].data.fd;
memset(buf, 0, BUFSIZE);
int n = read(curfd, buf, BUFSIZE);
recvtime++;
if(n<=0){
close(curfd);
}
else{
// printf("recv %s\n", buf);
close(curfd);
}
}
}
if(recvtime==SENDTIME){
break;
}
}
}
int costms(timeval *v1, timeval *v2){
if(v2->tv_usec < v1->tv_usec){
v2->tv_sec--;
v2->tv_usec+=1000000;
}
return (v2->tv_sec - v1->tv_sec)*1000+(v2->tv_usec - v1->tv_usec)/1000;
}
void test(){
worker();
}
int main(){
timeval v1,v2;
gettimeofday(&v1,NULL);
test();
gettimeofday(&v2,NULL);
int cost = costms(&v1, &v2);
printf("cost:%dms\n", cost);
}
测试发现,当上一篇中的多线程同步发送客户端为单线程时,速度慢于这里的client_single,符合预期。 但当线程数为10或更多时,发送接收同样总个数的请求,多线程同步的程序速度快于 这里的单进程异步。
而且这里的单进程异步存在一个问题:
因为一个fd发送完数据后,要将其放入epoll监听,等接收到返回数据后再关闭fd。这就导致有大量的fd为打开状态,很容易达到系统最大的fd个数,不能再创建新的fd。
所以我的想法是,对于客户端,适合用多线程的同步模式发送接收数据。仅仅是在单一场景下的想法,欢迎大家讨论。