基于TCP的不同IO版本的时间性能分析
来源:互联网 发布:当店家软件 编辑:程序博客网 时间:2024/06/06 17:00
一、关于各种IO的执行情况分析
涉及的IO类型:
基本堵塞IO版本、
select下堵塞IO版本、
非堵塞IO版本、
fork版本、
线程化版本。
服务器核心代码:
dg_echo.c
#include "unp.h"voidstr_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 = %d\n", ++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 1024voidstr_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):%lf\n", (double)((end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec))/1000000); printf("GET: %f\n", (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 1024void 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):%lf\n", (double)((end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec))/1000000); printf("GET: %f\n", (double)recvtotalsize/(NUM * LENGTH)); return; }else{ recvtotalsize += n; } } if(stdineof == 0 && FD_ISSET(sockfd, &wset)){ // write nwritten = write(sockfd, sendbuf, LENGTH); if(nwritten < 0){ if(errno != EWOULDBLOCK) fprintf(stderr, "write error to socket\n"); }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){// child for(;;){ if ((n = read(sockfd, recvline, MAXLINE)) == 0){ err_quit("str_cli: server terminated prematurely"); break; }else if(n < 0){ fprintf(stderr, " read error from socket\n"); } else{ total += n; if(total == NUM * LENGTH){ break; } } } gettimeofday(&end, NULL); printf("use times(s):%lf\n", (double)((end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec))/1000000); printf("GET: %f\n", (double)total/(NUM * LENGTH)); //Fputs(recvbuf, stdout); kill(getppid(), SIGTERM); // in case parents kill running exit(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
#include "unp.h"#define NUM 1048576#define LENGTH 1024void 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):%lf\n", (double)((end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec))/1000000); printf("GET: %f\n", (double)recvtotalsize/(NUM * LENGTH)); return; }else{ recvtotalsize += n; } } if(stdineof == 0 && FD_ISSET(sockfd, &wset)){ // write nwritten = write(sockfd, sendbuf, LENGTH); if(nwritten < 0){ if(errno != EWOULDBLOCK) fprintf(stderr, "write error to socket\n"); }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类型效率低, 可能是因为网络负载的问题, 也可能是本程序设计不够充分,有待提高。(具体分析任然还有待考验,请等待试验更新)
- 基于TCP的不同IO版本的时间性能分析
- duird.io 支持不同版本的 hadoop
- 基于Overlapped IO的TCP服务器模型
- IO---Java 不同读写方式的IO性能
- MySQL不同版本间的性能比较
- HttpClient不同版本超时时间的设置
- 算法的时间性能分析
- 算法的时间性能分析
- 算法的时间性能分析
- 分析浏览器的时间性能
- 性能分析之IO分析-jbd2引起的IO高
- jdk版本不同引起的问题分析
- 基于TCP连接的RTSP协议分析
- 西门子PLC200不同版本的串口性能比较
- 西门子PLC200不同版本的串口性能比较
- 西门子PLC200不同版本的串口性能比较
- mysql性能测试及不同版本的比较
- mysql性能测试及不同版本的比较
- Android 平板通过USB口连接小票打印机
- Android Support兼容包详解
- 欢迎使用CSDN-markdown编辑器
- 南阳ACM-喷水装置(二)
- Java 自学的成长路径
- 基于TCP的不同IO版本的时间性能分析
- QWidget的六个刷新函数(居然有QWidget::erase函数,且并不产生绘制事件)
- 解析xml的4种方法详解
- 视频播放,Raw和assets文件夹
- 查看linux中某个端口(port)是否被占用
- 02. Servlet 主要API介绍
- MTU设置
- SecureCRT 连接ubuntu操作系统(解决Ubuntu密钥交换失败的问题)
- 自定义滚轮选择器Wheelview