关闭

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

标签: 网络编程read和writeread阻塞write阻塞
3073人阅读 评论(3) 收藏 举报
分类:
         刚刚接触网络编程时,很容易被客户端和服务器之间的交互搞晕,例如各种函数的阻塞和非阻塞就让人头疼。例如在我的印象中
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服务器端程序:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>

#define BUF_SIZE 100 

void error_handling(char* message);

int main(int argc,char* argv[])

{
	int serv_sock,clnt_sock;
	struct sockaddr_in serv_addr,clnt_addr;
	int clnt_addr_sz;
	int str_len,i,j;
	char buf[BUF_SIZE];

	if(argc!=2)
	{
		printf("Usage %s <port>\n",argv[0]);
		exit(1);
	}
	//创建socket
	serv_sock=socket(AF_INET,SOCK_STREAM,0);
	if(serv_sock==-1)
		error_handling("socket error");
	//填充地址信息
	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family=AF_INET;
	serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	serv_addr.sin_port=htons(atoi(argv[1]));
	//socket和ip地址的绑定
	if(bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1)
		error_handling("bind error");
	//开启监听
	if(listen(serv_sock,5)==-1)
		error_handling(" listen error");
    	sleep(10);
	for(i=0;i<5;i++)
	{
		clnt_addr_sz=sizeof(clnt_addr);
		clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_addr,&clnt_addr_sz);
		if(clnt_sock==-1)
			error_handling("accept error");
		else
			printf("clnt:%s connected\n",inet_ntoa(clnt_addr.sin_addr));
		//接受数据
		while(1)
		{
			str_len=read(clnt_sock,buf,BUF_SIZE);
				write(clnt_sock,buf,str_len);
			memset(buf,0,sizeof(buf));
			if(str_len<=0)
				break;
		}
		close(clnt_sock);
	}
	close(serv_sock);
	return 0;
}


void error_handling(char* message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}
        请留意在调用 listen()开启监听后的sleep(10),我们让服务器睡了10s中,以此来验证客户端程序在read时发生阻塞,服务器 睡醒后才结束阻塞状态。
客户端的代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<time.h>
#define BUF_SIZE 10000000

void print_time();

void error_handling(const char* message);

int main(int argc,char* argv[])
{
	int sock;
	struct sockaddr_in serv_addr;
	int str_len;
	char buf[BUF_SIZE];
	int recv_len=0;
	//创建socket
	sock=socket(AF_INET,SOCK_STREAM,0);
	if(sock==-1)
		error_handling("socket error");

	//准备地址
	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family=AF_INET;
	serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
	serv_addr.sin_port=htons(atoi(argv[2]));

	//链接
	if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1)
		error_handling("connect error");
	else
	        puts("connect succeed");
	while(1)
	{
		memset(buf,0,BUF_SIZE);
		fputs("请输入数据:",stdout);
		fgets(buf,BUF_SIZE,stdin);
		if(!strcmp(buf,"q\n")||!strcmp(buf,"Q/n"))
			break;

		str_len=write(sock,buf,strlen(buf));
		puts("writed,begin block");
		print_time();
		sizeof(buf,0,sizeof(buf));
		while(recv_len<str_len)
			recv_len+=read(sock,buf,BUF_SIZE-1);
		puts("end block");
		print_time();
		buf[str_len]=0;
		printf("服务器传回信息:%s\n",buf);
	}
	close(sock);
	return 0;
}

void print_time()
{
  time_t now=time(0);
	struct tm* ptm=localtime(&now);
	char buf[256]={0};
	sprintf(buf,"time now:[%02d-%02d-%02d %02d:%02d:%02d]",
  		ptm->tm_year+1900,
			ptm->tm_mon+1,
			ptm->tm_mday,
			ptm->tm_hour,
			ptm->tm_min,
			ptm->tm_sec);
	puts(buf);
}

void error_handling(const char* message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}

        客户端在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

0
0
查看评论

linux串口编程--规范模式和非规范模式及read的阻塞与非阻塞

1/阻塞与非阻塞 阻塞的定义 对于read,指当串口输入缓冲区没有数据的时候,read函数将会阻塞在这里,直到串口输入缓冲区中有数据可读取,read读到了需要的字节数之后,返回值为读到的字节数; 对于write,指当串口输出缓冲区满,或剩下的空间小于将要写入的字节数,则writ...
  • xieyi2015
  • xieyi2015
  • 2016-04-10 18:01
  • 3963

linux系统编程之基础必备(七):read/write函数与(非)阻塞I/O的概念

一、read/write 函数 read函数从打开的设备或文件中读取数据。 #include ssize_t read(int fd, void *buf, size_t count); 返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次rea...
  • Simba888888
  • Simba888888
  • 2013-05-20 16:40
  • 9299

read函数的阻塞和非阻塞的区别

读常规文件是不会阻塞的,不管读多少字节,read一定会在有限的时间内返回。从终端 设备或网络读则不一定,如果从终端输入的数据没有换行符,调用read读终端设备就会阻 塞,如果网络上没有接收到数据包,调用read从网络读就会阻塞,至于会阻塞多长时间也是 不确定的,如果一直没有数据到达就一直阻塞在那里。...
  • qq_25048473
  • qq_25048473
  • 2016-12-03 16:36
  • 825

深入理解linux下write()和read()函数

1、write() 函数定义:ssize_t write (int fd, const void * buf, size_t count); 函数说明:write()会把参数buf 所指的内存写入count 个字节到参数fd 所指的文件内。 当然,文件读写位置也会随之移动。 返回值:如果顺利writ...
  • hhhlizhao
  • hhhlizhao
  • 2017-05-13 20:09
  • 1563

阻塞和非阻塞read/write

read函数 调用read函数从大
  • u012317833
  • u012317833
  • 2014-09-17 16:13
  • 7731

read( ) 函数 —— 终端输入设备的阻塞与非阻塞的设置

read( ) 函数 —— 终端输入设备的阻塞与非阻塞的设置
  • lile777
  • lile777
  • 2015-12-30 19:50
  • 2698

linux read() 函数

read()函数   2011-03-23 16:28:37|  分类: linux |  标签: |字号大中小 订阅 read 函数从打开的设备或文件中读取数据。 #include ...
  • hjhcs121
  • hjhcs121
  • 2012-04-14 15:28
  • 97881

read函数---------详解

read函数从打开的设备或文件中读取数据。 #include ssize_t read(int fd, void *buf, size_t count); 返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0 参数 cou...
  • CSDN_logo
  • CSDN_logo
  • 2015-06-15 09:15
  • 9689

Linux中阻塞函数的超时处理

由于gethostbyname是阻塞的,且不可重入的,超时时间过程,人为设置超时时间可用如上方法。
  • zsf8701
  • zsf8701
  • 2015-07-17 10:25
  • 1092

linux中阻塞机制

一,阻塞与非阻塞 阻塞是指没有获得资源则挂起进程,直到获得资源为止。被挂起的进程进入休眠状态,被调度器的运行队列移走,直到等待条件被满足。 非阻塞是不能进行设备操作时不挂起,或放弃,或反复查询,直到可以进行操作为止。 驱动程序常需要这种能力:当应用程序进行read(),write()等系统调用...
  • tong646591
  • tong646591
  • 2013-01-09 14:15
  • 5597
    个人资料
    • 访问:511935次
    • 积分:7962
    • 等级:
    • 排名:第3122名
    • 原创:303篇
    • 转载:17篇
    • 译文:1篇
    • 评论:72条
    其它平台
    博客专栏