基于TCP的不同IO版本的时间性能分析

阅读: 评论:0

基于TCP的不同IO版本的时间性能分析

基于TCP的不同IO版本的时间性能分析

一、关于各种IO的执行情况分析

涉及的IO类型:

基本堵塞IO版本、

select下堵塞IO版本、

非堵塞IO版本、

fork版本、

线程化版本。


服务器核心代码:

dg_echo.c

#include    "unp.h"void
str_echo(int sockfd)
{ssize_t     n;char        buf[MAXLINE];int counter = 0;
again:while ( (n = read(sockfd, buf, MAXLINE)) > 0){Writen(sockfd, buf, n);//printf("counter = %dn", ++counter);}if (n < 0 && errno == EINTR)goto again;else if (n < 0)err_sys("str_echo: read error");
}


本次试验是基于TCP回射服务器分析, 通过发送100MB的数据, 然后回射接受100MB, 并且计算其运行时间, 服务器程序将会统一运行,以此来分析,在堵塞IO, select下堵塞IO, 非堵塞IO的select版本, 以及堵塞IO的fork版本的运行时间和代码分析

1、基本堵塞IO

源代码如下所示:

dg_cli01.c

#include    "unp.h"#define NUM 1048576
#define LENGTH 1024
void
str_cli(FILE *fp, int sockfd)
{char    sendline[MAXLINE], recvline[MAXLINE];struct timeval start, end;gettimeofday(&start, NULL);int n = 0 ;int total = 0;int i;for(i = 0; i < NUM; ++i){write(sockfd, sendline, LENGTH);if ((n = read(sockfd, recvline, MAXLINE)) == 0)err_quit("str_cli: server terminated prematurely");if (n >= 0) total += n;//Fputs(recvline, stdout);}gettimeofday(&end, NULL);printf("use times(s):%lfn", (double)((end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec))/1000000);printf("GET: %fn", (double)total/(NUM * LENGTH));
}

分析:

1、每次代码发送1KB的数据, 然后堵塞等待服务器回射。

2、socket的发送空间每次也只是利用了1024kb,利用不充分

3、本代码中通过接受的总字节数,与发送的总字节数作比较。通常会计算式数据的获得的率。是一个小于等于1的整数

运行结果:


结果分析:本次结果,可以判断出, 通常情况下是在30-31ms之间, 如果接受幅度变动较大可能根据网络负载有很大的关系。


2、select下的堵塞IO模型

核心源代码分如下:

dg_cli_blockio_select01.c

#include "unp.h"
#define NUM 1048576
#define LENGTH 1024
void str_cli(FILE *fp, int sockfd){ssize_t n, nwritten;char sendbuf[MAXLINE], recvbuf[MAXLINE];int sendtotalsize = 0;int recvtotalsize = 0;struct timeval start, end;gettimeofday(&start, NULL);fd_set rset, wset;int stdineof = 0;for(;;){FD_ZERO(&rset);FD_ZERO(&wset);if(stdineof == 0)   FD_SET(sockfd, &wset);FD_SET(sockfd, &rset);select(sockfd + 1, &rset, &wset, NULL, NULL);if(FD_ISSET(sockfd, &rset)){n = read(sockfd, recvbuf, MAXLINE);if(n < 0){if(errno != EWOULDBLOCK)fprintf(stderr, "read error from socket.n");}else if(n == 0){gettimeofday(&end, NULL);printf("use times(s):%lfn", (double)((end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec))/1000000);printf("GET: %fn", (double)recvtotalsize/(NUM * LENGTH));return;}else{recvtotalsize += n;}}if(stdineof == 0 && FD_ISSET(sockfd, &wset)){ // writenwritten = write(sockfd, sendbuf, LENGTH);if(nwritten < 0){if(errno != EWOULDBLOCK) fprintf(stderr, "write error to socketn");}else{sendtotalsize += nwritten;if(sendtotalsize == NUM * LENGTH){  // write 100MB data finished.stdineof = 1;shutdown(sockfd, SHUT_WR);}}}}
}
分析:

1、当socket不可读的时候, 可以持续往socket里面发送数据, 这样不会因为read堵塞导致进程休眠,提高了效率。

2、在read读取数据的时候, 可以读取socket接受缓冲区中所有的数据。

3、当数据发送完毕后, 调用shutdown函数, 发送FIN分节

4、read返回0, 代表对FIN分节做出了应答, 服务器关闭。本次结束。


运行结果如下:

结果分析:相对于一中的基本堵塞IO模型,效率大大的提高了三倍, 因为通过select使得进程因为堵塞而休眠的时间更少。


3、fork下的堵塞IO

源代码如下:

dg_cli_fork01.c

#include "unp.h"#define LENGTH 1024
#define NUM 1048576void str_cli(FILE *fp, int sockfd){pid_t child;char sendline[MAXLINE],recvline[MAXLINE];struct timeval start, end;gettimeofday(&start, NULL);int n = 0 ;int total = 0;int i;if((child = fork()) == 0){// childfor(;;){if ((n = read(sockfd, recvline, MAXLINE)) == 0){err_quit("str_cli: server terminated prematurely");break;}else if(n < 0){fprintf(stderr, " read error from socketn");}else{total += n;if(total == NUM * LENGTH){break;}}}gettimeofday(&end, NULL);printf("use times(s):%lfn", (double)((end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec))/1000000);printf("GET: %fn", (double)total/(NUM * LENGTH));//Fputs(recvbuf, stdout);kill(getppid(), SIGTERM);   // in case parents kill runningexit(0);}for(i = 0; i < NUM; ++i){write(sockfd, sendline, LENGTH);}Shutdown(sockfd, SHUT_WR);pause();
}
分析如下;

1、通过子进程接受来至服务器的数据, 父进程想服务器发送数据。

2、父进程发送数据完毕后,强制通过shutdown发送FIN分节,如果是调用close也仅仅只是引用计数减一

3、当子进程接收到了为0的时候,那么则数据传输完毕,子进程结束, 并且发送SIGTERM给父进程


结果:传输100MB的数据在回射回来,明显效率明显高于1、2中的模型。


4、select下非堵塞IO

源代码如下: dg_cli_nonblock01.c

#include "unp.h"
#define NUM 1048576
#define LENGTH 1024
void str_cli(FILE *fp, int sockfd){ssize_t n, nwritten;char sendbuf[MAXLINE], recvbuf[MAXLINE];int sendtotalsize = 0;int recvtotalsize = 0;struct timeval start, end;gettimeofday(&start, NULL);fd_set rset, wset;int flag = Fcntl(sockfd, F_GETFL, 0);Fcntl(sockfd, F_SETFL, flag | O_NONBLOCK);int stdineof = 0;for(;;){FD_ZERO(&rset);FD_ZERO(&wset);if(stdineof == 0)   FD_SET(sockfd, &wset);FD_SET(sockfd, &rset);select(sockfd + 1, &rset, &wset, NULL, NULL);if(FD_ISSET(sockfd, &rset)){n = read(sockfd, recvbuf, MAXLINE);if(n < 1){if(errno != EWOULDBLOCK)fprintf(stderr, "read error from socket.n");}else if(n == 0){gettimeofday(&end, NULL);printf("use times(s):%lfn", (double)((end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec))/1000000);printf("GET: %fn", (double)recvtotalsize/(NUM * LENGTH));return;}else{recvtotalsize += n;}}if(stdineof == 0 && FD_ISSET(sockfd, &wset)){ // writenwritten = write(sockfd, sendbuf, LENGTH);if(nwritten < 0){if(errno != EWOULDBLOCK) fprintf(stderr, "write error to socketn");}else{sendtotalsize += nwritten;if(sendtotalsize == NUM * LENGTH){  // write 100MB data finished.stdineof = 1;shutdown(sockfd, SHUT_WR);}}}}
}
分析如下:

1、代码与三中的代码区别唯一的区别就是,调用fcntl函数,设置IO类型



运行结果:从理论上的非堵塞IO的select类型的效率是明显高于堵塞IO类型的, 但是实际的结果是比fork的堵塞io类型效率低, 可能是因为网络负载的问题, 也可能是本程序设计不够充分,有待提高。(具体分析任然还有待考验,请等待试验更新


本文发布于:2024-02-02 09:48:58,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170683854142993.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:性能   版本   时间   TCP   IO
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23