Linux 网络编程——TCP多进程聊天程序

实现目标

【1】创建TCP服务器和客户端,实现简易聊天程序;
【2】数据收发单独进程实现;
【3】客户端/服务器任一结束,结束连接和对方进程。

服务器端(server)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/prctl.h>
#include <arpa/inet.h>
#include <errno.h>
#include <resolv.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>

void sig_parent_handle(int signo)
{
	printf("receive process child signal\n");
	if(waitpid(-1, NULL, 0) < 0) 
  	{
    	perror("waitpid error:");
  	}
	exit(0);
}

void sig_child_handle(int signo)
{
	if (signo == SIGHUP)
	{				   
		printf("receive process parent SIGHUP signal\n");
		exit(0);
	}
}

int main (int argc, char * argv[])
{
	int s_fd, c_fd, pid; 
	socklen_t addr_len;
	struct sockaddr_in s_addr, c_addr;
	char buf[1024];
	ssize_t size = 0;
	
	if(argc != 3)
	{
		printf("format error!\n");
		printf("usage: server <address> <port>\n");
		exit(1);
	}

	/* 进程通知信号 */
	signal(SIGCHLD,sig_parent_handle);
	
	/* 服务器端地址 */ 
	s_addr.sin_family = AF_INET;
	s_addr.sin_port   = htons(atoi(argv[2]));
	if(!inet_aton(argv[1], (struct in_addr *) &s_addr.sin_addr.s_addr))
	{
		perror("invalid ip addr:");
		exit(1); 
	}
	
	/* 创建socket */
	if((s_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
	{
		perror("socket create failed:"); 
		exit(1); 
	} 

	/* 端口重用,调用close(socket)一般不会立即关闭socket,而经历“TIME_WAIT”的过程 */
	int reuse = 0x01;
	if(setsockopt(s_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(int)) < 0)
	{
		perror("setsockopt error");
		close(s_fd);
		exit(1); 
	}
	
	/* 绑定地址 */
	if(bind(s_fd, (struct sockaddr*)&s_addr, sizeof(s_addr)) < 0)
	{
		perror("bind error");
		close(s_fd);
		exit(1); 
	}
	
	/* 监听socket */
	if(listen(s_fd, 5) < 0)
	{
		perror("listen error");
		close(s_fd);
		exit(1); 
	}
	addr_len = sizeof(struct sockaddr);
	c_fd = accept(s_fd, (struct sockaddr*)&c_addr, (socklen_t *)&addr_len);
	
	if(c_fd < 0)
	{
		perror("accept error");
		close(s_fd);
		exit(1); 
	}
	else
	{
		printf("connected with ip: %s and port: %d\n", inet_ntop(AF_INET,&c_addr.sin_addr, buf, 1024), ntohs(c_addr.sin_port));
	}
	printf("waiting client connecting\r\n");

	/* 创建进程 */
	pid = fork();
	if(pid < 0) 
	{
		perror("fork error");
		exit(1);
	}

	if(pid == 0)  /* 子进程发送消息 */
	{
		signal(SIGHUP, sig_child_handle);
        prctl(PR_SET_PDEATHSIG, SIGHUP);
		  
		for(; ;)
		{
			printf("please enter message to send:\n"); 
			fflush(stdout);
			memset(buf, 0, sizeof(buf)); 
			size = read(STDIN_FILENO, buf, sizeof(buf) - 1); 	
			if(size > 0) 
			{
				buf[size - 1] = '\0'; 
			} 
			else if(size == 0)
			{
				printf("read is done...\n"); 
				break; 
			}
			else
			{
				perror("read stdin error"); 
				break; 
			}
			if(!strncmp(buf, "quit", 4))
			{
				printf("close the connect!\n");
				break;
			}
			if(buf[0] == '\0')
			{
				continue;
			}
			size = write(c_fd, buf, strlen(buf)); 
			if(size <= 0)
			{
				printf("message'%s' send failed!errno code is %d,errno message is '%s'\n",buf, errno, strerror(errno));
				break;
			}
		}
	}
	else 			/* 父进程接收消息 */
	{
		for(;;)
		{
			memset(buf, 0, sizeof(buf)); 
			size = read(c_fd, buf, sizeof(buf) - 1);
			if(size > 0)
			{
				printf("message recv %dByte: \n%s\n",size,buf);
			}
			else if(size < 0)
			{
				printf("recv failed!errno code is %d,errno message is '%s'\n",errno, strerror(errno));
				break;
			}
			else
			{
				printf("client disconnect!\n");
				break;
			}
		}
	}
	close(s_fd); 
	close(c_fd);

	return 0;
}

客户端(client)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h> 
#include <sys/types.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/prctl.h>

void sig_parent_handle(int sig)
{
	printf("receive process child signal\n");

	if(waitpid(-1, NULL, 0) < 0) 
  	{
    	perror("waitpid error:");
  	}
	exit(0);
}

void sig_child_handle(int signo)
{
	if (signo == SIGHUP)
	{				   
		printf("receive process parent SIGHUP signal\n");
		exit(0);
	}
}

int main (int argc, char * argv[])
{ 
	int c_fd,pid; 
	int ret;
	struct sockaddr_in s_addr;
	socklen_t addr_len;
	char buf[1024]; 
	ssize_t size;

	if(argc != 3)
	{
		printf("format error!\n");
		printf("usage: client <address> <port>\n");
		exit(1);
	}

	/* 进程通知信号 */
	signal(SIGCHLD,sig_parent_handle);
	
	/* 创建socket */
	c_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(c_fd < 0)
	{
		perror("socket create failed");
		return -1;
	} 
 
	/* 服务器端地址 */ 
	s_addr.sin_family 	= AF_INET;
	s_addr.sin_port 	= htons(atoi(argv[2]));
	if(!inet_aton(argv[1], (struct in_addr *) &s_addr.sin_addr.s_addr))
	{
		perror("invalid ip addr");
		exit(1); 
	}

	/* 连接服务器*/
	addr_len = sizeof(s_addr);
	ret = connect(c_fd, (struct sockaddr*)&s_addr, addr_len); 
	if(ret < 0)
	{
		perror("connect server failed");
		exit(1);  
	} 

	/* 创建进程 */
	pid = fork();
	if(pid < 0) 
	{
		perror("fork error");
		exit(1);
	}

	if(pid == 0)		/* 子进程发送消息 */
	{
		signal(SIGHUP, sig_child_handle);
        prctl(PR_SET_PDEATHSIG, SIGHUP);
		
		for(;;)
		{
			memset(buf, 0, sizeof(buf)); 
			printf("please enter message to send:\n"); 
			fflush(stdout);
			
			memset(buf, 0, sizeof(buf)); 
			size = read(STDIN_FILENO, buf, sizeof(buf) - 1); /* 从终端读取输入信息 */
			if(size > 0) 
			{
				buf[size - 1] = '\0'; 
			} 
			else if(size == 0)
			{
				printf("read is done...\n"); 
				break; 
			}
			else
			{
				perror("read stdin error"); 
				break; 
			}
			if(!strncmp(buf, "quit", 4))
			{
				printf("close the connect!\n");
				break;
			}
			if(buf[0] == '\0')
			{
				continue;
			}
			size = write(c_fd, buf, strlen(buf)); 
			if(size <= 0)
			{
				printf("message'%s' send failed!errno code is %d,errno message is '%s'\n",buf, errno, strerror(errno));
				break;
			}
		}
	}
	else				/* 父进程接收消息 */
	{
		for(;;)
		{
			size = read(c_fd, buf, sizeof(buf)); /* 读取服务器消息 */
			if(size > 0) 
			{  
				printf("message recv %dByte: \n%s\n",size,buf);
			} 
			else if(size < 0)
			{
				printf("recv failed!errno code is %d,errno message is '%s'\n",errno, strerror(errno));
				break;
			} 
			else
			{
				printf("server disconnect!\n");
				break;
			}  
		}
	}
	
	close(c_fd); 

	return 0; 
}

执行效果
在这里插入图片描述

posted @ 2019-08-21 23:42  Acuity  阅读(100)  评论(0编辑  收藏  举报