当前位置:   article > 正文

网络编程(24)—— linux中write和read函数的阻塞试验_linux write 阻塞

linux write 阻塞
         刚刚接触网络编程时,很容易被客户端和服务器之间的交互搞晕,例如各种函数的阻塞和非阻塞就让人头疼。例如在我的印象中
linux中用于用于对文件描述符进行读写的write()函数和read()函数是非阻塞函数,但是在一次网络通信的试验中发现它们又是阻
塞的,后来man了一下write和read,发现其文档中都有下面一句话:



ERRORS
       EAGAIN The file descriptor fd refers to a file other than a  socket  and  has  been

              marked non-blocking (O_NONBLOCK), and the write would block.

翻译过来就是:
         如果文件描述符不是socket的话,该函数是非阻塞的,否则该函数是阻塞的。 为了验证这个问题,进行如下实验,主要验证read函数的阻塞特性(验证write函数需要填充满输出缓冲区,我不会!!!)
        首先编写socket服务器端程序:

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>
  4. #include<sys/socket.h>
  5. #include<arpa/inet.h>
  6. #define BUF_SIZE 100
  7. void error_handling(char* message);
  8. int main(int argc,char* argv[])
  9. {
  10. int serv_sock,clnt_sock;
  11. struct sockaddr_in serv_addr,clnt_addr;
  12. int clnt_addr_sz;
  13. int str_len,i,j;
  14. char buf[BUF_SIZE];
  15. if(argc!=2)
  16. {
  17. printf("Usage %s <port>\n",argv[0]);
  18. exit(1);
  19. }
  20. //创建socket
  21. serv_sock=socket(AF_INET,SOCK_STREAM,0);
  22. if(serv_sock==-1)
  23. error_handling("socket error");
  24. //填充地址信息
  25. memset(&serv_addr,0,sizeof(serv_addr));
  26. serv_addr.sin_family=AF_INET;
  27. serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
  28. serv_addr.sin_port=htons(atoi(argv[1]));
  29. //socket和ip地址的绑定
  30. if(bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1)
  31. error_handling("bind error");
  32. //开启监听
  33. if(listen(serv_sock,5)==-1)
  34. error_handling(" listen error");
  35. sleep(10);
  36. for(i=0;i<5;i++)
  37. {
  38. clnt_addr_sz=sizeof(clnt_addr);
  39. clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_addr,&clnt_addr_sz);
  40. if(clnt_sock==-1)
  41. error_handling("accept error");
  42. else
  43. printf("clnt:%s connected\n",inet_ntoa(clnt_addr.sin_addr));
  44. //接受数据
  45. while(1)
  46. {
  47. str_len=read(clnt_sock,buf,BUF_SIZE);
  48. write(clnt_sock,buf,str_len);
  49. memset(buf,0,sizeof(buf));
  50. if(str_len<=0)
  51. break;
  52. }
  53. close(clnt_sock);
  54. }
  55. close(serv_sock);
  56. return 0;
  57. }
  58. void error_handling(char* message)
  59. {
  60. fputs(message,stderr);
  61. fputc('\n',stderr);
  62. exit(1);
  63. }
        请留意在调用 listen()开启监听后的sleep(10),我们让服务器睡了10s中,以此来验证客户端程序在read时发生阻塞,服务器 睡醒后才结束阻塞状态。
客户端的代码:
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>
  4. #include<sys/socket.h>
  5. #include<arpa/inet.h>
  6. #include<time.h>
  7. #define BUF_SIZE 10000000
  8. void print_time();
  9. void error_handling(const char* message);
  10. int main(int argc,char* argv[])
  11. {
  12. int sock;
  13. struct sockaddr_in serv_addr;
  14. int str_len;
  15. char buf[BUF_SIZE];
  16. int recv_len=0;
  17. //创建socket
  18. sock=socket(AF_INET,SOCK_STREAM,0);
  19. if(sock==-1)
  20. error_handling("socket error");
  21. //准备地址
  22. memset(&serv_addr,0,sizeof(serv_addr));
  23. serv_addr.sin_family=AF_INET;
  24. serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
  25. serv_addr.sin_port=htons(atoi(argv[2]));
  26. //链接
  27. if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1)
  28. error_handling("connect error");
  29. else
  30. puts("connect succeed");
  31. while(1)
  32. {
  33. memset(buf,0,BUF_SIZE);
  34. fputs("请输入数据:",stdout);
  35. fgets(buf,BUF_SIZE,stdin);
  36. if(!strcmp(buf,"q\n")||!strcmp(buf,"Q/n"))
  37. break;
  38. str_len=write(sock,buf,strlen(buf));
  39. puts("writed,begin block");
  40. print_time();
  41. sizeof(buf,0,sizeof(buf));
  42. while(recv_len<str_len)
  43. recv_len+=read(sock,buf,BUF_SIZE-1);
  44. puts("end block");
  45. print_time();
  46. buf[str_len]=0;
  47. printf("服务器传回信息:%s\n",buf);
  48. }
  49. close(sock);
  50. return 0;
  51. }
  52. void print_time()
  53. {
  54. time_t now=time(0);
  55. struct tm* ptm=localtime(&now);
  56. char buf[256]={0};
  57. sprintf(buf,"time now:[%02d-%02d-%02d %02d:%02d:%02d]",
  58. ptm->tm_year+1900,
  59. ptm->tm_mon+1,
  60. ptm->tm_mday,
  61. ptm->tm_hour,
  62. ptm->tm_min,
  63. ptm->tm_sec);
  64. puts(buf);
  65. }
  66. void error_handling(const char* message)
  67. {
  68. fputs(message,stderr);
  69. fputc('\n',stderr);
  70. exit(1);
  71. }

        客户端在write之后,打印出"writed,begin block"的信息,然后read函数开始阻塞,只有在服务端sleep完,返回数据后才会结束阻塞,结果如下:
服务端-

[Hyman@Hyman-PC echoSever]$ ./serv 9190
time now:[2016-10-09 09:28:04]
clnt:127.0.0.1 connected

客户端-

[Hyman@Hyman-PC echoSever]$ ./clnt 127.0.0.1 9190
connect succeed
请输入数据:helo
writed,begin block
time now:[2016-10-09 09:28:01]
end block
time now:[2016-10-09 09:28:04]
服务器传回信息:helo

以上代码,足以证明了read函数的阻塞特性。。。。。


Github位置:
https://github.com/HymanLiuTS/NetDevelopment
克隆本项目:
git clone git@github.com:HymanLiuTS/NetDevelopment.git
获取本文源代码:
git checkout NL24

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/343366
推荐阅读
相关标签
  

闽ICP备14008679号