linux中write和read函数的阻塞试验

bte365娱乐场 📅 2025-09-21 16:07:51 👤 admin 👁️ 636 ❤️ 339
linux中write和read函数的阻塞试验

原文:https://blog.csdn.net/hyman_c/article/details/52979317

刚刚接触网络编程时,很容易被客户端和服务器之间的交互搞晕,例如各种函数的阻塞和非阻塞就让人头疼。例如在我的印象中 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

#include

#include

#include

#include

#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 \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

#include

#include

#include

#include

#include

#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

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

相关推荐

远程控制模块有哪些类型?
365不给提款流水数据异常

远程控制模块有哪些类型?

📅 09-19 👁️ 1254
牧马人与猛禽二者相较哪个更佳?
365bet娱乐场

牧马人与猛禽二者相较哪个更佳?

📅 07-21 👁️ 413
【世界杯】竞猜世界杯球赛,给您几点小提醒
bte365娱乐场

【世界杯】竞猜世界杯球赛,给您几点小提醒

📅 07-05 👁️ 2187