linux 聊天室

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<sys/shm.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<signal.h>
#include<time.h>

const int SVKEY=75;
unsigned short port = 8990;	// 本地端口

int sockfd;
struct user
{
	char id[50];
	int connfd;
};
struct user client;
int connfd = 0;

void setserver()
{	
	//创建套接字
	sockfd = socket(AF_INET, SOCK_STREAM, 0);   
	if(sockfd < 0)
	{
		perror("socket");
		exit(-1);
	}
	//设置本地地址结构体
	struct sockaddr_in my_addr;
	bzero(&my_addr, sizeof(my_addr));			// 清空,保证最后8字节为0    
	my_addr.sin_family = AF_INET;				// ipv4
	my_addr.sin_port   = htons(port);			// 端口
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);// ip,INADDR_ANY为通配地址其值为0
	//将本地ip、端口与套接字socket相关联起来
	int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
	if( err_log == -1)
	{
		perror("binding");
		close(sockfd);		
		exit(-1);
	}
	//监听,监听套接字改为被动,创建连接队列
	err_log = listen(sockfd, 10); 
	if(err_log == -1)
	{
		perror("listen");
		close(sockfd);		
		exit(-1);
	}	
	printf("server at port=%d...\n",port);
}
 
//得到当前系统的时间
void gettime(char *time)
{
    struct timeval now;
    gettimeofday(&now, NULL);
    strcpy(time, ctime(&now.tv_sec));
}
 
void sendtoall(int connfd,int shmid)
{
	char compare[512]="END";	//将END设置为结束通讯的标志
	char recv_buf[512] = "";
	char send_buf[512]="";
	
	pid_t pid=fork();
	if(pid>0)//父进程读发送的消息 同步到共享内存
	{
		char *buff=(char *)shmat(shmid,NULL,0);
		while(recv(connfd, recv_buf, sizeof(recv_buf), 0)>0)
		{
			if(strcmp(compare,recv_buf)==0)	//判断是否断开连接
			{
				kill(pid,SIGKILL);//杀死子进程
				wait(NULL);
				printf("client %s closed!\n",client.id);
				close(connfd);     //关闭已连接套接字
				break;
			}
			bzero(buff,sizeof(buff));
			sprintf(buff,"%s:%s",client.id,recv_buf);
			bzero(recv_buf,strlen(recv_buf));
		}
	}
	else if(pid==0)//子进程读共享内存的消息
	{
		char *buff=(char *)shmat(shmid,NULL,0);
		while(1)
		{
			if(strlen(buff)>0)
			{
					char id[50];
					char temp[512];
					sprintf(temp,"%s",buff);
					/*获取发送信息的id*/
					for(int i=0;i<50;i++)
					{
					if(temp[i]-':'!=0)	id[i]=temp[i];///
						else break;
					}
					if(strcmp(id,client.id)!=0)
					{
						char time[100];
						gettime(time);
						sprintf(send_buf,"%s\t%s",time,temp);
						int s=send(connfd,send_buf,strlen(send_buf),0);
						if(s<0)	perror("send");
						bzero(send_buf,strlen(send_buf));
					}
					bzero(id,strlen(id));
					bzero(buff,strlen(buff));
			}
		}
	}
}
 
void ctoc(int connfd,int shmchatid)
{
 	char send_buf[512];
	char recv_buf[512];
	int fd=open("/home/hujing/hj/idinf",O_RDONLY);
	bzero(send_buf,sizeof(send_buf));
	read(fd,send_buf,sizeof(send_buf));
	close(fd);
	int s=send(connfd,send_buf,strlen(send_buf),0);
	if(s<0) perror("send");
 	pid_t pid=fork();
 	if(pid==0)
	{
		char *buff=(char *)shmat(shmchatid,NULL,0);
		bzero(buff,sizeof(buff));
		/*read all friends*/
		bzero(send_buf,sizeof(send_buf));
		bzero(recv_buf,sizeof(recv_buf));
 		recv(connfd,recv_buf,sizeof(recv_buf),0);
 		// 写入共享内存
 		while(1) if(strlen(buff)==0)	break;//当共享内存为空 输入共享内存
		sprintf(buff,"%s",recv_buf);
		//printf("1.%s %d recv=%s\n",client.id,(int)strlen(recv_buf),recv_buf);
		bzero(recv_buf,sizeof(recv_buf));
 	}
 	else if(pid>0)
 	{
 		char *buff=(char *)shmat(shmchatid,NULL,0);
 		bzero(buff,sizeof(buff));
		while(1)
		{
			if(strlen(buff)>0)
			{	/*获取发送信息的id*/
				char temp[512];
				sprintf(temp,"%s",buff);
				char id[50];
				bzero(id,sizeof(id));
				for(int i=0;i<50;i++)
				{
					if(temp[i]-':'!=0)	id[i]=temp[i];
					else break;
				}
				//printf("3.%s %s\n",client.id,id);
				if(strcmp(id,client.id)!=0)
				{
					//printf("2.%s recv %s\n",client.id,temp);
					int s=send(connfd,temp,strlen(temp),0);
					//if(s>0) printf("%d\n",s);
					bzero(buff,sizeof(buff));
					break;
				}
				bzero(buff,sizeof(buff));
			}
		}
		wait(NULL);
 	}
}
 
void commu(int connfd,int shmid,int shmchatid)
{
	char recv_buf[512];
	char send_buf[512];
	/*read client id*/
	recv(connfd, recv_buf, sizeof(recv_buf), 0);
	for(int i=0;i<strlen(recv_buf);i++)
	client.id[i]=recv_buf[i];
	client.connfd=connfd;
	int fd=open("/home/hujing/hj/idinf",O_WRONLY|O_APPEND);//将client.id写入文件
	sprintf(send_buf,"%s\t",client.id);
	write(fd,send_buf,strlen(send_buf));
	bzero(send_buf,strlen(send_buf));
	bzero(recv_buf,strlen(recv_buf));
	close(fd);
	/*read client select*/
	recv(connfd,recv_buf,sizeof(recv_buf),0);
	char select=recv_buf[1];
	bzero(recv_buf,strlen(recv_buf));
	switch(select)
	{
	case '1':sendtoall(connfd,shmid);break;//群聊
	case '2':ctoc(connfd,shmchatid);break;//私聊
	}
}
 
int main(int argc, char *argv[])
{
	setserver();
	
	struct sockaddr_in client_addr;		   
	char cli_ip[INET_ADDRSTRLEN] = "";	   //INET...是ipv4的长度
	socklen_t cliaddr_len = sizeof(client_addr);    //socklen_t 一种数据类型 accept函数中第三个参数的长度必须和int相同  32和64位 下的socklen_t和int长度不同

	umask(0000);
	int fd=open("/home/hujing/hj/idinf",O_CREAT|O_TRUNC,0777);//存储id
	int shmid=shmget(SVKEY,512,IPC_CREAT|0777);//创建共享内存
	int shmchatid=shmget(76,512,IPC_CREAT|0777);//创建共享内存
	while(1)
	{	
		connfd=0;
		//从完成连接队列中提取客户端连接
		connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);       
		if(connfd < 0)
		{
			perror("accept");
			continue;
		}
		inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);
		printf("\nclient ip=%s,port=%d,connfd=%d\n", cli_ip,ntohs(client_addr.sin_port),connfd);
		
		pid_t pid=fork();
		if(pid==0)
		{
			close(sockfd);
			commu(connfd,shmid,shmchatid);
			close(connfd);
			exit(0);
		}
	}
	close(sockfd);         //关闭监听套接字
	return 0;
}

client.c

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include<sys/types.h>
#include<signal.h>
#include<sys/shm.h>
 
unsigned short port = 8990;        		// 服务器的端口号
char *server_ip = "127.0.0.1";    	// 服务器ip地址
int sockfd;
char send_buf[512] = "";
char recv_buf[512]="";
char compare[512]="END";	//将END设置为结束通讯的标志
char id[50];
 
void setclient()
{
	sockfd = socket(AF_INET, SOCK_STREAM, 0);// 创建套接字
	if(sockfd < 0)
	{
		perror("socket");
		exit(-1);
	}
	// 设置服务器地址结构体
	struct sockaddr_in server_addr;
	bzero(&server_addr,sizeof(server_addr)); // 初始化服务器地址
	server_addr.sin_family = AF_INET;	// IPv4
	server_addr.sin_port = htons(port);	// 端口
	inet_pton(AF_INET, server_ip, &server_addr.sin_addr.s_addr);	// 转换ip地址格式
	 // 主动连接服务器
	int err_log = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));     
	if(err_log != 0)
	{
		perror("connect");
		close(sockfd);
		exit(-1);
	}
}
 
void sendtoall()
{
	printf("\tINPUT ANY SENTENCES YOU WANT\n");
	pid_t pid=fork();
	/*send message*/
	if(pid>0)
	{
		while(1)
		{	
			//printf("%s:",id);
			printf(">>>");
			scanf("%s",send_buf);
			send(sockfd, send_buf, strlen(send_buf), 0);   // 向服务器发送信息
			if(strcmp(compare,send_buf)==0)	//判断是否断开连接
			{
				kill(pid,SIGKILL);
				wait(NULL);
				printf("%s close the connection!\n",id);
				close(sockfd);
				break;
			}
			bzero(send_buf,strlen(send_buf));	//清空发送缓冲区
		}
	}
	/*receive message*/
	else if(pid==0)
	{
		while(1)
		{
			int r=recv(sockfd,recv_buf,sizeof(recv_buf),0);
			printf("\n\t%s\n",recv_buf);
			bzero(recv_buf,strlen(recv_buf));
		}
	}
}
 
void sendtoone()
{
	/*send chat id*/
	bzero(recv_buf,strlen(recv_buf));
	recv(sockfd, recv_buf, sizeof(recv_buf), 0);
	printf("friends:%s\n",recv_buf);

	int fd[2];
	int flag=pipe(fd);//创建管道
	if(flag==-1) perror("pipe error");
 
	pid_t pid=fork();//创建子进程
	if(pid==0)//子进程 接收私聊请求
	{
		close(fd[0]);
		bzero(recv_buf,sizeof(recv_buf));
		recv(sockfd, recv_buf, sizeof(recv_buf), 0);
		write(fd[1],recv_buf,strlen(recv_buf));
		exit(0);
	}
	else if(pid>0)//父进程 读取后终止
	{
		close(fd[1]);
		printf(">>>chat with and password(number):");
		char chatid[50];
		char chatkey[20];
		scanf("%s %s",chatid,chatkey);
		bzero(send_buf,sizeof(send_buf));
		sprintf(send_buf,"%s:%s-%s",id,chatid,chatkey);
		send(sockfd,send_buf,strlen(send_buf),0);
		bzero(send_buf,strlen(send_buf));
		
		read(fd[0],recv_buf,sizeof(recv_buf));
		
		char sendid[50];
		char myid[50];
		char sendkey[20];
		bzero(sendid,sizeof(sendid));
		bzero(myid,sizeof(myid));
		bzero(sendkey,sizeof(sendkey));
		int i=0;
		for(;i<(int)strlen(recv_buf);i++)
			if(recv_buf[i]-':'!=0)	sendid[i]=recv_buf[i];
			else break;
		i++;
		for(int j=0;i<(int)strlen(recv_buf);i++,j++)
			if(recv_buf[i]-'-'!=0)	myid[j]=recv_buf[i];
			else break;
		i++;
		for(int j=0;i<(int)strlen(recv_buf);i++,j++)
			sendkey[j]=recv_buf[i];
		//printf("%s %s %s\n",sendid,myid,sendkey);
		if(strcmp(sendid,chatid)==0&&strcmp(myid,id)==0&&strcmp(chatkey,sendkey)==0)
		{
			printf("\tstart communication with %s\n",sendid);
			int key=0;
			sscanf(sendkey,"%d",&key);
			//printf("%d\n",key);
			int shmid=shmget(key,512,IPC_CREAT|0777);	
			pid_t ppid=fork();
			if(ppid>0)//子进程 发
			{
				char *buff=(char *)shmat(shmid,NULL,0);
				while(1)
				{
					printf(">>>");
					bzero(send_buf,sizeof(send_buf));
					scanf("%s",send_buf);
					if(strcmp(compare,send_buf)==0)	//判断是否断开连接
					{
						kill(ppid,SIGKILL);//杀死子进程
						wait(NULL);
						printf("%s close the connection!\n",id);
						close(sockfd);     //关闭已连接套接字
						break;
					}
					bzero(buff,sizeof(buff));			
					sprintf(buff,"%s:%s",id,send_buf);
					bzero(send_buf,sizeof(send_buf));
				}	
			}
			else if(ppid==0)//父进程 收
			{
				char *buff=(char *)shmat(shmid,NULL,0);
				while(1)
				{
					if(strlen(buff)>0)
					{
						char chatid[50];
						bzero(chatid,sizeof(chatid));
						char temp[512];
						bzero(temp,sizeof(temp));
						sprintf(temp,"%s",buff);
						/*获取发送信息的id*/
						for(int i=0;i<50;i++)
						{
						if(temp[i]-':'!=0)	chatid[i]=temp[i];
							else break;
						}
						if(strcmp(chatid,id)!=0)
						{
							printf("\n\t%s\n",temp);
						}
						bzero(chatid,sizeof(chatid));
						bzero(buff,sizeof(buff));
					}
					
				}
			}
		}
		wait(NULL);
	}
}
 
int main(int argc, char *argv[])
{
	setclient();
	
	/*send client id*/
	printf("your id:");
	scanf("%s",id);
	send(sockfd,id,strlen(id),0);
	/*select communication type*/	
	printf("\t请选择通讯方式\n");
	printf("\t1.client-server-all\n");
	printf("\t2.client-client\n");
	int select=0;
	scanf("%d",&select);
	send_buf[0]='*';
	switch(select)
	{
	case 1:send_buf[1]='1';break;
	case 2:send_buf[1]='2';break;
	}
	send_buf[2]='*';
	send(sockfd,send_buf,strlen(send_buf),0);
	bzero(send_buf,strlen(send_buf));
	switch(select)
	{
	case 1:sendtoall();break;
	case 2:sendtoone();break;
	}
	
	close(sockfd);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值