【Linux网络编程】基于TCP多进程(fork)版本客户端/服务器


客户端代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static usage(const char* proc)
{
	printf("%s [ip] [port\n]", proc);
}

int main(int argc, char** argv)
{
	if(argc != 3)
	{
		usage(argv[0]);
		exit(1);
	}

	int sock = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in server;
	if(sock < 0)
	{
		perror("socket");
		return 1;
	}
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = inet_addr(argv[1]);
	server.sin_port = htons(atoi(argv[2]));

	if(connect(sock ,(struct sockaddr*)&server, sizeof(server) ) < 0)
	{
		perror("connect");
		exit(4);
	}

	char buf[1024];

	while(1)
	{
		printf("please input #: ");
		fflush(stdout);
		ssize_t sread = read(0, buf, sizeof(buf)-1);
		if(sread > 0)
		{
			buf[sread-1] = 0;
			write(sock, buf, strlen(buf));
			printf("server $ %s\n", buf);
			read(sock, buf, sizeof(buf) - 1);
		}
	
	}



	close(sock);
}



服务端代码:

#include 
#include    //
#include   // socket()  bind()
#include 
#include 
#include 
#include 
#include 

// 使用帮助
static void usage(const char* proc)
{
	printf("use help : %s [local_ip] [local_port]\n", proc);
}

// 创建并绑定一个socket
int startup(const char* _ip, int _port)
{
	// 创建一个socket
	int sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0)
	{
		perror("----sock----fail\n");
		exit(-1);
	}

	// 绑定一个本地socket
	struct sockaddr_in local;
	local.sin_family = AF_INET;
	local.sin_addr.s_addr = inet_addr(_ip);
	local.sin_port = htons(_port);

	if(bind(sock, (struct sockaddr*)&local, sizeof(local)) != 0)
	{
		perror("---bind---fail\n");
		close(sock);
		exit(-2);
	}

	if(listen(sock, 5) != 0)
	{
		perror("----listen----fail\n");
		close(sock);
		exit(-1);
	}

	return sock;		
}

int main(int argc, char**argv)
{
	if(argc != 3)
	{
		usage(argv[0]);
		return -1;
	}

	// 获取一个local socket
	int listen_sock = startup(argv[1], atoi(argv[2]));
	struct sockaddr_in client;
	socklen_t len = sizeof(client);

	char buf[1024];
	while(1)
	{
		int new_sock = accept(listen_sock,(struct sockaddr*)&client, &len);
		if(new_sock < 0)
		{
			perror("----accept----fail\n");
			close(listen_sock);
			exit(-5);
		}
		pid_t id = fork();
		if(id == 0)
		{
			// ///////////////可以再这里fork 然后退出子进程,这样负责监听的进程PID就不会一直变//////////
			close(listen_sock); // 子进程已经获得 sockfd, 不需要listen sock所以关闭
			while(1)
			{
			    ssize_t s = read(new_sock,buf, sizeof(buf)-1);
			    if(s > 0 )
			    {
			    	buf[s] = 0;
			    	printf("client say## %s \n", buf);
			    	write(new_sock, buf, strlen(buf));
			    }
				else if( s == 0)
				{
					printf("client quit. \n");
					break;
				}
				else
					break;
			}
			exit(0);

		}
		else if (id > 0)
		{
			// 父进程
			// 在父进程中fork退出的话,会导致监听进程的pid一直在变,所以我们也可以再子进程中fork然后退出
			close(new_sock); // 此时子进程已经获取 sockfd, 父进程只需要监听sockfd,又因为每次fork都会赋值描述符,为了节省资源,关闭new_sock
			if(fork() > 0)
			{
				exit(0);
			}
			// 父进程退出,此时第二次fork出的子进程 成为孤儿进程,此后它产生的子进程退出时由系统来回收资源
		}
	}


	return 0;
}




截图:

启动服务端:

【Linux网络编程】基于TCP多进程(fork)版本客户端/服务器_第1张图片

 
  


开启一个终端查看状态可以看到已经在监听:

【Linux网络编程】基于TCP多进程(fork)版本客户端/服务器_第2张图片


然后启动两个客户端模拟多个连接:

1.启动客户端1

【Linux网络编程】基于TCP多进程(fork)版本客户端/服务器_第3张图片

2.然后查看连接状态,可以发现已经建立连接

【Linux网络编程】基于TCP多进程(fork)版本客户端/服务器_第4张图片

然后再启动一个进程,建立连接:

【Linux网络编程】基于TCP多进程(fork)版本客户端/服务器_第5张图片

观察状态:

【Linux网络编程】基于TCP多进程(fork)版本客户端/服务器_第6张图片




我们会发现负责Listen进程的的PID一直在变,是因为我们是在父进程中fork然后让父进程退出,让子进程继续监听,所以一直会变,我们可以使用一个小技巧,在子进程中fork一个进程,让父进程不变。



你可能感兴趣的:(linux)