一个看似诡异的错误

先上代码
客户端代码如下:
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

void str_cli(FILE *stream, int fd);

int main(int argc, char* argv[])
{
	if (argc < 2)
	{
		fprintf(stdout, "Usage: %s ip_address", argv[0]);
	}

	int socket_fd[5];
	int i;
	for(i = 0; i < 5; i++)
	{
		socket_fd[i] = socket(AF_INET, SOCK_STREAM, 0);

		struct sockaddr_in server_addr;
		memset(&server_addr, 0, sizeof(server_addr));
		inet_pton(AF_INET, argv[1], &(server_addr.sin_addr.s_addr));
		server_addr.sin_port = htons(13500);
		server_addr.sin_family = AF_INET;

		printf("%d", i);
		if ((connect(socket_fd[i], (struct sockaddr *) &server_addr, sizeof(server_addr))) == -1)
		{
			printf("socket %d connect failed.", i);
		}
	}
	str_cli(stdin, socket_fd[0]);

	return 0;
}

void str_cli(FILE *stream, int fd)
{
	char buff[5000];

	char read_buff[5000];
	printf("begin to read\n");
	while((fgets(buff, sizeof(buff), stream)) != NULL)
	{

		fprintf(stderr, "%s\n", buff);
		write(fd, buff, strlen(buff));
		read(fd, read_buff, sizeof(read_buff));
		fprintf(stdout, "$%s\n", read_buff);
		printf("begin to read\n");
	}
}

服务器端代码如下:
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <errno.h>

void str_echo(int fd);
void sig_chld(int signal);

int main()
{
	signal(SIGCHLD, sig_chld);

	int connect_fd, listen_fd;
	listen_fd = socket(AF_INET, SOCK_STREAM, 0);
	
	struct sockaddr_in client_addr, server_addr;
	memset(&server_addr, 0, sizeof(server_addr));
	memset(&client_addr, 0, sizeof(client_addr));
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(13500);

	bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
	listen(listen_fd, 100);

	while(1)
	{
		socklen_t client_addr_length = sizeof(client_addr);
		if ((connect_fd = 
					accept(listen_fd, (struct sockaddr *) &client_addr, &client_addr_length) 
					< 0))
		{
			printf("connect_fd is %d\n", connect_fd);
			if (EINTR == errno)
			{
				continue;
			}
			else
			{
				return -1;
			}
		}

		pid_t child_pid;
		if ((child_pid = fork()) == 0)
		{
			//child process
			close(listen_fd);
			str_echo(connect_fd);
			exit(0);
		}
		
		close(connect_fd);

	}
}

void str_echo(int fd)
{
	char buff[5000];
	int read_length;
	
	while (1)
	{
		printf("1\n");
		if ( (read_length = read(fd, buff, sizeof(buff))) > 0)
		{
			printf("%s\n", buff);
			write(fd, buff, read_length);
			printf("%s\n", buff);
		}
		else
		{
			printf("2\n");
			return;
		}
	}
		
}

void sig_chld(int signal)
{
	pid_t pid;
	int status;
	pid = wait(&status);
	printf("child %d terminated!\n", signal);
	
	return;
}



程序的预期功能是:
客户端从标准输入读入一行,发送到服务器,服务器接受到消息一行,将该消息回送到客户端,客户端将接受到回送消息显示在标准输出上。

bug特征:
第一次打开客户端,输入字符,不能正确回显,消息阻塞在read部分,不关闭服务端,重启客户端,工具就能正常工作。

bug分析:
服务端程序的
if ((connect_fd = 
					accept(listen_fd, (struct sockaddr *) &client_addr, &client_addr_length) 
					< 0))

括号加错了位置。第一次开启客户端程序的时候,connect_fd被错误的赋值为1,导致其accept、read、write都在标准输入上进行。但是执行到
close(connect_fd);

的时候,标准输入被关闭,当关闭客户端程序再次打开的时候,accept返回的的结果是当前最小fd,该fd为0,0<0的结果为0,阴差阳错,connect_fd被赋予了正确的fd,所以第二次,程序就能正常工作。所以初学者看上去诡异的bug就出现了。感谢文卿大牛啊。

经验教训:
如果按照编程规范进行,就能避免很多着由看似不起眼的小问题出现的bug.....编程规范!!!!

猜你喜欢

转载自sunny-y.iteye.com/blog/1233791