Prueba de bloqueo de funciones de escritura y lectura en linux

Original: https://blog.csdn.net/hyman_c/article/details/52979317

Cuando entra en contacto por primera vez con la programación de la red, es fácil confundirse con la interacción entre el cliente y el servidor. Por ejemplo, el bloqueo y no bloqueo de varias funciones es un dolor de cabeza. Por ejemplo, en mi impresión, la función write () y la función read () que se usan para leer y escribir descriptores de archivos en Linux son funciones sin bloqueo, pero en un experimento de comunicación de red, se encontró que estaban bloqueando. Más tarde, man After leyendo, escribiendo y leyendo, encontré la siguiente oración en el documento:

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.

La traducción es:
si el descriptor de archivo no es un socket, la función no es bloqueante; de ​​lo contrario, la función está bloqueada. Para verificar este problema, se llevan a cabo los siguientes experimentos para verificar las características de bloqueo de la función de lectura (para verificar que la función de escritura necesita llenar el búfer de salida, yo no lo haré !!!)

Primero escriba el programa del lado del servidor de 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);
}

Preste atención a dormir (10) después de llamar a listen () para activar la supervisión. Dejamos que el servidor duerma durante 10 segundos para verificar que el programa cliente esté bloqueado durante la lectura y que el estado de bloqueo finalice después de que el servidor se active.

Codigo del cliente:

#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);
}

El cliente después de escribir, imprima la información "escrita, comience el bloqueo" y luego lea la función de inicio de bloqueo, terminó de dormir solo en el lado del servicio, el bloqueo terminará después de que se devuelvan los datos con los siguientes resultados:
servidor -

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

Cliente-

[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

El código anterior es suficiente para probar las características de bloqueo de la función de lectura. . . . .

Ubicación de Github:
https://github.com/HymanLiuTS/NetDevelopment
Clone este proyecto:
git clone [email protected]: HymanLiuTS / NetDevelopment.git
Obtenga el código fuente de este artículo:
git checkout NL24

Supongo que te gusta

Origin blog.csdn.net/xiaolei251990/article/details/83586973
Recomendado
Clasificación