1.libco协程客户端
场景如下:
tcp_sever:接受客户端连接,处理客户端请求,5s后回包,模拟rpc阻塞式调用服务
tcp_client:连接tcp服务器,发送请求,等待回包,这里qps! 0.2/s
libco_echocli:连接tcp服务器,起n个协程,qps! 0.2*n/s
注意:
1)这里把tcp_server的处理时间设置为了5分钟,所以libco库的读写超时时间要比这个大,这里都直接设置成10s了,在文件co_hook_sys_call.cpp
static inline rpchook_t * alloc_by_fd( int fd )
{
rpchook_t *lp = (rpchook_t*)calloc( 1,sizeof(rpchook_t) );
lp->read_timeout.tv_sec = 10;
lp->write_timeout.tv_sec = 10;
...
}
1.场景1:tcp_client连接
[[email protected]:~/Documents/test_tcp]$./client
3 time:1564800489 send req!
3 time:1564800494 recv rsp!
ret:15, server response
服务器:
[[email protected]:~/Documents/test_tcp]$./server
fd:5 client 1564800489 req:heklko
fd:5 client 1564800494 rsp:server response
5 fd normal close
2.协程:./example_echocli 127.0.0.1 8888 1000 1
起1000个协程
top:虚拟机单核cpu占用10%_15%
qps: 1000/5,每秒并发200个
客户端:
服务器:
2)https://blog.csdn.net/hhyjiayou/article/details/80661666 这篇文章讲会将socket设置为非阻塞
实际上这里是没设置的,阻塞形式的io在读空 写满的时候会导致进程挂起,实际这里读写的时候fd还是阻塞的,只不过设置了一个超时时间,比如说read的时候,注册了一个epoll事件监听相关io,只有io到来的时候,或者超时了,才会通知到协程来处理,如果io是非阻塞式的,直接使用系统原生的read write了,
152 int flags = 0;
153 if(flags = fcntl(fd, F_GETFL, 0) < 0)
154 {
155 perror("fcntl");
156 }
157 if(flags & O_NONBLOCK)
158 {
159 //printf("%d no block\n", fd);
160 }
161 else
162 {
163 //printf("%d block\n", fd);
164 }
执行结果:
[
况且libco微信的分析也只是说把这部分异步化了,并没有说把fd设置为非阻塞了,
tcp_sever.cpp:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLEN 1024
#include
#include
tcp_client.c:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_EXIT(m) \
do { \
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
#define MAXLINE 1024
static void do_client(int fd)
{
char recvbuf[MAXLINE + 1] = {0};
char sendbuf[MAXLINE + 1] = {0};
fd_set reade, ready;
FD_ZERO(&reade);
int fd_stdin = fileno(stdin);
FD_SET(fd_stdin, &reade);
FD_SET(fd, &reade);
int fd_max = (fd_stdin > fd) ? fd_stdin : fd;
int ret;
while(1)
{
ready = reade;
ret = select( fd_max+1, &ready, NULL, NULL, NULL);//轮询
if(ret == -1)
{
if(errno == EINTR)
continue;
ERR_EXIT("select");
}else if(ret == 0)
{
continue;
}
if(FD_ISSET(fd_stdin, &ready))
{
if(fgets(sendbuf, sizeof(sendbuf), stdin) == NULL)
{
close(fd);
break;
}else
{
if( -1 == write(fd, sendbuf, strlen(sendbuf)))
printf("write\n");
}
}
if(FD_ISSET(fd, &ready))
{
int nread = read(fd, recvbuf, MAXLINE);
if(nread < 0)
ERR_EXIT("read");
if(nread == 0)//如果没接收到消息,打印关闭描述符,退出循环
{
fprintf(stdout, "fd close\n");
break;
}
fprintf(stdout, "receive:%s", recvbuf);
}
memset(recvbuf, 0, sizeof recvbuf);
memset(sendbuf, 0, sizeof sendbuf);
}
}
void handle(int signum)
{
printf("sigpipe\n");
}
int main(int argc, const char *argv[])
{
signal(SIGPIPE, SIG_IGN);
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd < 0)
ERR_EXIT("socket");
struct sockaddr_in cliaddr;
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(8888);
cliaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
socklen_t len = sizeof cliaddr;
int ret ;
if((ret = connect(fd, (struct sockaddr*)&cliaddr, len)) == -1)
{
close(fd);
ERR_EXIT("connect");
}
struct linger so_linger;
so_linger.l_onoff = 1;
so_linger.l_linger=1;
//设置延迟关闭
setsockopt(fd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
// do_client(fd);
write(fd, "heklko", 7);
printf("%d time:%lu send req!\n", fd, time(NULL));
char str[1024] = {0};
ret = read(fd, str, 1024);
if(ret)
{
printf("%d time:%lu recv rsp!\n", fd, time(NULL));
printf("ret:%d, %s\n", ret, str);
}
close(fd);
return 0;
}
example_echocli.cpp 用Libco里面的demo即可,注意测试时要把Libco的读写超时设置得比服务器处理时间大,不然一直返回errno 11,