5月25号作业

基于UDP的网络聊天室
项目需求:
1.如果有用户登录,其他用户可以收到这个人的登录信息
2.如果有人发送信息,其他用户可以收到这个人的群聊信息
3.如果有人下线,其他用户可以收到这个人的下线信息
4.服务器可以发送系统信息

网络聊天室---------服务器

#include "headea.h"
#define SER_IP "192.168.126.27"
#define SER_PORT 8888
int main(int argc, const char *argv[])
{
	//1.创建结构体
	int sfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sfd==-1){
		perror("socket");
		return -1;
	}
	printf("socket success\n");
	//2.设置端口号快速重启
	int reuse=1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1){
		perror("setsockopt");
		return -1;
	}
	printf("setsockopt success\n");
	//3.绑定IP和端口号
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(SER_PORT);
	sin.sin_addr.s_addr=inet_addr(SER_IP);
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1){
		perror("bind");
		return -1;
	}
	printf("bind success\n");
	//4.数据交互
	struct sockaddr_in cin;            //客户端发送过来的地址
	socklen_t cinlen=sizeof(cin);
	char cbuf[255];
	//创建用户地址结构体
	int maxi=0;
	struct sockaddr_in rin[100]; //创建用户地址结构体数组
	//创建用户信息结构体
	Msg_t* H=Head_creat();   //创建头结点
	//IO多路复用
	struct pollfd pfds[2];
	pfds[0].fd=0;
	pfds[0].events=POLLIN;
	pfds[1].fd=sfd;
	pfds[1].events=POLLIN;
	char name[20];
	char passwd[20];
	while(1){
		int res=poll(pfds,2,-1);
		if(res==0){
			printf("timr out\n");
			return 0;
		}
		if(res==-1){
			perror("poll");
			return -1;
		}
		//执行到此处说明接发信息被触发
		if(pfds[1].revents==POLLIN){
			bzero(cbuf,sizeof(cbuf));
			recvfrom(sfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&cin,&cinlen);
			char* p1=cbuf;
			char cfs[211]="";
			strcpy(cfs,p1+41);
			//	printf("cbuf:%s\ncfs:%s\n",p1+41,cfs);
			if(cbuf[0]=='Z'){                                   //表示用户注册
				bzero(name,sizeof(name));
				bzero(passwd,sizeof(passwd));
				char* p1=cbuf;
				strncpy(name,p1+1,20);
				strncpy(passwd,p1+21,20);
				//
				printf("注册用户信息%s||%s\n",name,passwd);     //*********测试用
				//
 
				if(find_node(H,name,passwd)==0){ //如果用户列表不存在则允许创建
					tail_inst(H,name,passwd);        //用户信息存入链表
					bzero(cbuf,sizeof(cbuf));
					cbuf[0]='Y';
					strcpy(p1+41,"注册成功,欢迎登录聊天系统"); //将成功信息返回客户端
 
					//	printf("rin[maxi].sin_port=%hd ,rin[maxi].sin_addr.s_addr=%s\n",ntohs(rin[maxi-1].sin_port),inet_ntoa(rin[maxi-1].sin_addr));
					//	printf("cin.sin_port=%hd ,cin.sin_addr.s_addr=%s\n",ntohs(cin.sin_port),inet_ntoa(cin.sin_addr));
 
					sendto(sfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&cin,sizeof(cin));
				}else if(find_node(H,name,passwd)!=0){     //用户已存在并通知客户端
					bzero(cbuf,sizeof(cbuf));
					cbuf[0]='N';
					strcpy(p1+41,"用户已存在,请重新输入");   //将失败信息返回客户端
					sendto(sfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&cin,sizeof(cin));
				}
			}
			else if(cbuf[0]=='L'){                                 //表示用户登录
				bzero(name,sizeof(name));
				bzero(passwd,sizeof(passwd));
				char* p1=cbuf;
				strncpy(name,p1+1,20);
				strncpy(passwd,p1+21,20);
				int res=find_node(H,name,passwd);
				if(res==1){
					if(maxi>1024){  //判断登录用户是否过载
						cbuf[0]='N';
						strcpy(p1+41,"登录用户已满,请等待后重试\n");
						sendto(sfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&cin,sizeof(cin));
						break;
					}
					rin[maxi]=cin;    //*************************将登录信息存入注册数组中
					maxi++;
			
					/*	int i=0;
						while(1){
						if(rin[i].sin_addr.s_addr=='\0'){
						rin[i]=cin;
						break;
						}
						i++;   //最小未使用找出i
						}
						if(maxi<i){
						maxi=i;  //留下最大已使用的下标
						printf("maxi=%d\n",maxi);  ********测试用(暂时弃用)
						}*/
					printf("%s:已登录\n",name);                   //给服务端发送提示
					cbuf[0]='Y';
					strcpy(p1+41,"已登录");          //将上线信息发送给所有用户
					for(int j=0;j<maxi;j++){
						sendto(sfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&rin[j],sizeof(rin[j]));
					}
				}else if(res==2){  //密码错误,用户重新输入
					cbuf[0]='N';
					strcpy(p1+41,"密码错误,请重试\n");
					sendto(sfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&cin,sizeof(cin));
				}else if(res==0){
					cbuf[0]='N';
					strcpy(p1+41,"暂无该用户,请注册\n");
					sendto(sfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&cin,sizeof(cin));
				}
			}
			else if(cbuf[0]=='C'){                               //表示用户聊天
				char* p1=cbuf;
				bzero(name,sizeof(name));
				cbuf[0]='Y';
				strncpy(name,p1+1,20);
 
				for(int j=0;j<maxi;j++){
					sendto(sfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&rin[j],sizeof(rin[j]));
					printf("rin[%d].sin_port=%d ,rin[maxi].sin_addr.s_addr=%s\n",j,ntohs(rin[j].sin_port),inet_ntoa(rin[j].sin_addr));
					//printf("cin.sin_port=%d ,cin.sin_addr.s_addr=%s\n",ntohs(cin.sin_port),inet_ntoa(cin.sin_addr));
				}
				printf("用户%s信息发送成功\n",name);
 
			}
			else if(cbuf[0]=='Q'){                                //表示用户退出
				cbuf[0]='Y';
				char* p1=cbuf;
				strcpy(p1+41,"已下线");  
 
				//定义结构体rin[n],将下线信息发送给其他客户 
				for(int j=0;j<=maxi;j++){
					sendto(sfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&rin[j],sizeof(rin[j]));
				}
			}
			printf("ss:%s\n",cbuf);
		}
		if(pfds[0].revents==POLLIN){  //向所有客户端发送通知
			bzero(cbuf,sizeof(cbuf));
			char* p1=cbuf;
			char buf[211]="";
			cbuf[0]='Y';
			strcpy(p1+1,"Server:");
			fgets(buf,sizeof(buf),stdin);
			buf[strlen(buf)-1]='\0';
			strcpy(p1+41,buf);
 
			//	show(H);   //********测试用
 
			for(int j=0;j<maxi;j++){
				sendto(sfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&rin[j],sizeof(rin[j]));
				//	printf("rin[%d].sin_port=%d ,rin[maxi].sin_addr.s_addr=%s\n",j,ntohs(rin[maxi-1].sin_port),inet_ntoa(rin[maxi-1].sin_addr));
				//	printf("客户端说了\n");
			}
		}
	}
	//5.关闭文件
	close(sfd);
	return 0;
}

网络聊天室------结构体部分 

#include "header.h"
 
//创建头结点
Msg_t*  Head_creat(){
	Msg_t* H=(Msg_t*)malloc(sizeof(Msg_t));
	if(H==NULL){
		perror("malloc");
		return NULL;
	}
	H->next=NULL;
	return H;
}
 
//写入子节点
Msg_t* node_creat(const char* name,const char* passwd){
	Msg_t* new=(Msg_t*)malloc(sizeof(Msg_t));
	if(new==NULL){
		printf("子节点创建有问题\n");
		return NULL;
	}
	new->next=NULL;
	strcpy(new->name,name);
	strcpy(new->passwd,passwd);
	return new;
}
 
//尾插创建子节点
void tail_inst(Msg_t* H,const char* name,const char* passwd){
	if(H==NULL){
		printf("入参错误,请检查\n");
		return;
	}
	Msg_t* P=H;
	while(P->next!=NULL){
		P=P->next;
	}
	Msg_t* new=node_creat(name,passwd);
	P->next=new;
	printf("用户%s数据存储成功\n",name);
}
 
//遍历删除子节点
void del_pos_node(Msg_t* H,const char* name){
	if(H==NULL){
		printf("入参错误,请检查\n");
		return;
	}
	Msg_t* P=H;
	while(P->next!=NULL){
		if(strcmp(P->next->name,name)==0){
			Msg_t* q=P->next;
			P->next=q->next;
			free(q);
			break;
		}
		P=P->next;
	}
	printf("用户%s数据删除\n",name);
}
//遍历查询相同子节点
int find_node(Msg_t* H,const char* name,const char* passwd){
	if(H==NULL){
		printf("入参错误,请检查\n");
		return -1;
	}
	int num=0;
	Msg_t* P=H->next;
	while(P!=NULL){
		if(strcmp(P->name,name)==0){
			if(strcmp(passwd,P->passwd)==0){
				num=1;
			}else{
				num=2;
			}
		}
		P=P->next;
	}
//	printf("num=%d\n",num);  //*********测试用
	return num;
}
 
void show(Msg_t* H){
	Msg_t* P=H->next;
	while(P!=NULL){
		printf("%s->",P->name);
		P=P->next;
	}
	printf("结束show\n");
	putchar(10);
}

网路聊天室------客户端 

#include <header.h>
int main(int argc, const char *argv[])
{
	//1.输入要连接的端口号
	char ip[30]="";
	short pt=0;
	printf("请输入IP地址: ");
	scanf("%s",ip);
	while(getchar()!=10);
	printf("请输入端口号: ");
	scanf("%hd",&pt);
	while(getchar()!=10);
	//2.创建套接字
	int cfd=socket(AF_INET,SOCK_DGRAM,0);
	if(cfd==-1){
		perror("socket");
		return -1;
	}
	printf("socket success\n");
	//3.设置端口号快速重启
	int reuse=1;
	if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1){
		perror("socketopt");
		return -1;
	}
	printf("set setsockopt success\n");
	printf("登陆成功,请稍后\n");
	sleep(1);
 
	//循环执行功能界面
	//准备变量、结构体
	struct sockaddr_in cin;
	socklen_t cinlen=sizeof(cinlen);
	char cbuf[255];
 
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(pt);
	sin.sin_addr.s_addr=inet_addr(ip);
 
	//使用poll完成IO多路复用
	//
	//数据交互
	struct pollfd pfd[2];
	pfd[0].fd=0;
	pfd[1].fd=cfd;
	pfd[0].events=POLLIN;
	pfd[1].events=POLLIN;
	char name[20];
	char name1[20];
	char passwd[20];
	char buf[211];
	char cfs[211];
	char* p1=cbuf;
 
 
	printf("欢迎加入网络聊天室\n");
	while(1){
		printf("=======1.登录========\n");
		printf("=======2.注册========\n");
		printf("=======0.退出========\n");
		int num;
		scanf("%d",&num);
		while(getchar()!=10);
 
		switch(num){    
		case 1:         //登录、进入聊天界面
			{
				bzero(name,sizeof(name));
				bzero(passwd,sizeof(passwd));
				bzero(cbuf,sizeof(cbuf));
				bzero(buf,sizeof(buf));
				printf("请输入用户名:");
				scanf("%s",name);
				strcpy(name1,name);
				while(getchar()!=10);
				printf("请输入密码:");
				scanf("%s",passwd);
				while(getchar()!=10);
				cbuf[0]='L';
				strncpy(p1+1,name,20);
				strncpy(p1+21,passwd,20);              //将账户密码输入并等待服务端会话
				sendto(cfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&sin,sizeof(sin));
				bzero(cbuf,sizeof(cbuf));
				recvfrom(cfd,cbuf,sizeof(cbuf),0,NULL,NULL);
				if(cbuf[0]=='N'){
					printf("错误:%s\n",p1+41);
					break;
				}
				printf("登陆成功,欢迎\n");
				while(1){
					int res=poll(pfd,2,-1);
					if(res==0){
						printf("time out\n");
						return -1;
					}else if(res==-1){
						perror("poll");
						return -1;
					}                      //poll设立完成
 
					
					char cfs[211]="";
					if(pfd[0].revents==POLLIN){            //将消息发送给服务器
//*****
						bzero(cbuf,sizeof(cbuf));
						bzero(cfs,sizeof(cfs));
						cbuf[0]='C';
						strncpy(p1+1,name1,20);
//*****
						fgets(cfs,sizeof(cfs),stdin);
					//	printf("cfs:%s\n",cfs);
						cfs[strlen(cfs)-1]='\0';
						strcpy(p1+41,cfs);
					//	printf("cbuf:%s\n",p1+41);
					
 
						
						if(strcmp(cfs,"quit")==0){
							bzero(cbuf,sizeof(cbuf));
							cbuf[0]='Q';
							strcpy(p1+1,name1);
							sendto(cfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&sin,sizeof(sin));
							close(cfd);
							goto END;
						}
 
						sendto(cfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&sin,sizeof(sin));
					//	printf("发送成功\n");
					}
					if(pfd[1].revents==POLLIN){     //将从服务器接收到的信息发送给终端
						bzero(cbuf,sizeof(cbuf));
						bzero(name,sizeof(name));
						bzero(buf,sizeof(buf));
						recvfrom(cfd,cbuf,sizeof(cbuf),0,NULL,NULL);
						//char* p1=cbuf;
						//char name[20]="";
						strncpy(name,p1+1,20);
						strncpy(buf,p1+41,211);
						printf("%s:%s\n",name,buf);
					//	printf("接收成功\n");                  //***********测试用
					}
				}
			}
END:			break;
		case 2:     //注册
			{
				bzero(name,sizeof(name));
				bzero(passwd,sizeof(passwd));
				bzero(cbuf,sizeof(cbuf));
				printf("请输入注册名:");
				scanf("%20s",name);
				while(getchar()!=10);
				printf("请输入密码:");
				scanf("%20s",passwd);
				while(getchar()!=10);
				cbuf[0]='Z';
				strncpy(p1+1,name,20);
				strncpy(p1+21,passwd,20);
				sendto(cfd,cbuf,sizeof(cbuf),0,(struct sockaddr*)&sin,sizeof(sin));
				bzero(cbuf,sizeof(cbuf));
				recvfrom(cfd,cbuf,sizeof(cbuf),0,NULL,NULL);
 
				if(cbuf[0]=='N'){
					printf("错误:%s\n",p1+41);
					break;
				}else if(cbuf[0]='Y'){
					printf("%s\n",p1+41);
				}
			}
			break;
		case 0:     //退出客户端
			{
				printf("已退出聊天系统\n");
				return 0;
			}
			break;
		}
	}
}

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值