点对点聊天程序的实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wk_bjut_edu_cn/article/details/82318427

服务端

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
	do \
	{ \
		perror(m); \
		exit(EXIT_FAILURE); \
	}while(0)

//信号处理函数,将自身退出
void handler(int sig)
{
	printf("recv a dig=%d\n",sig);
	exit(EXIT_SUCCESS);
}
//只考虑一个服务端和一个客户端,不考虑一个服务端和多个客户端
int main(void)
{
	int listenfd;
	if((listenfd=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
		/*if((listenfd=socket(PF_INET,SOCK_STREAM,0))<0) */
		ERR_EXIT("socket");

	struct sockaddr_in servaddr;
	memset(&servaddr,0,sizeof(servaddr));
	servaddr.sin_family=AF_INET;
	servaddr.sin_port=htons(5188);
	servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
	/*servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");*/
	/*inet_aton("127.0.0.1,&servaddr.sin_addr");*/
	
	int on=1;
	if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0)
		ERR_EXIT("setsockopt");
	if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
		ERR_EXIT("bind");
	if(listen(listenfd,SOMAXCONN)<0)
		ERR_EXIT("listen");
	struct sockaddr_in peeraddr;
	socklen_t peerlen=sizeof(peeraddr);
	int conn;
	if((conn=accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen))<0)
		ERR_EXIT("accept");
	printf("ip=%s port=%d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
	//为了服务器端接收数据的同时还能发送数据,就需要创建一个进程出来
	//一个进程用来接收数据,另一个用来发送数据
	pid_t pid;
	pid=fork();
	if(pid==-1)
		ERR_EXIT("fork");
	//子进程用来发送数据
	if(pid==0)
	{
		//子进程收到父进程发送的信号
		//用户自定义的信号,关联一个处理函数
		signal(SIGUSR1,handler);
		char sendbuf[1024]={0};
		while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
		{
			write(conn,sendbuf,strlen(sendbuf));
			memset(sendbuf,0,sizeof(sendbuf));
		}
		printf("child close\n");
		exit(EXIT_SUCCESS);
	}
	//父进程用来获取数据
	//注意:当父进程退出时要通知子进程退出,可以通过信号的方式来实现
	else
	{
		char recvbuf[1024];
		while(1)
		 {
                 	 memset(recvbuf,0,sizeof(recvbuf));
                 	 int ret=read(conn,recvbuf,sizeof(recvbuf));
			 if(ret==-1)
			 {
			 	ERR_EXIT("read"); 
			 }
			 //说明对方关闭了
			 else if(ret==0)
			 {
			 	printf("peer close\n");
				break;
			 }
                 	 fputs(recvbuf,stdout);
         	 }
		printf("parent close\n");
		//当父进程退出的时候,向子进程发送一个信号,子进程的进程号码为pid
        //因为子进程还在等待从键盘输入
		kill(pid,SIGUSR1);
		exit(EXIT_SUCCESS);
	}
	return 0;
}

客户端

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
	do \
	{ \
		perror(m); \
		exit(EXIT_FAILURE); \
	}while(0)

//信号处理函数,父进程退出
void handler(int sig)
{
	printf("recv a sig=%d\n",sig);
	exit(EXIT_SUCCESS);
}
int main(void)
{
	int sock;
	if((sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
		/*if((listenfd=socket(PF_INET,SOCK_STREAM,0))<0) */
		ERR_EXIT("socket");

	struct sockaddr_in servaddr;
	memset(&servaddr,0,sizeof(servaddr));
	servaddr.sin_family=AF_INET;
	servaddr.sin_port=htons(5188);
	servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
	/*inet_aton("127.0.0.1,&servaddr.sin_addr");*/
	if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
		ERR_EXIT("connect");
	pid_t pid;
	pid=fork();
	if(pid==-1)
	{
		ERR_EXIT("fork");
	}
	if(pid==0)
	{
		char recvbuf[1024];
		while(1)
		{
			memset(recvbuf,0,sizeof(recvbuf));
			int ret=read(sock,recvbuf,sizeof(recvbuf));
			if(ret==-1)
				ERR_EXIT("read");
			else if(ret==0)
			{
				printf("peer close\n");
				break;
			}	
			fputs(recvbuf,stdout);
		}
		close(sock);
		//通知父进程退出,因为父进程还在等待键盘输入
		kill(getppid(),SIGUSR1);
	}
	else
	{
		//接收子进程发送过来的信号
		signal(SIGUSR1,handler);
		char sendbuf[1024]={0};
		while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
		{
			write(sock,sendbuf,strlen(sendbuf));
			memset(sendbuf,0,sizeof(sendbuf));
		}
		close(sock);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wk_bjut_edu_cn/article/details/82318427
今日推荐