服务端客户端通讯,注册,上线,下线,私聊,广播(UDP)

版权声明:请在征得作者同意的情况下,可以进行非盈利性引用。引用请注明出处:“作者:慕华思弦 转载地址” 字样,以尊重作者的劳动成果,并保持良好的版权意识。 https://blog.csdn.net/Superman___007/article/details/82928836

框架:C/S
Client:向服务器发送请求消息
     1、注册
     2、验证上线
     3、发送消息:广播消息/私人消息(******)
     4、退出消息(****)
     多进程开发:父进程接收信息   子进程:发送消息
Server:
    1、接收用户请求
            注册
           上线
          接收发送消息请求并转发 
            退出        
         总结:
         UDP:面向无连接,不安全,不可靠,无状态的传输协议

  服务器实现注册和上线的协议功能 :

#include<iostream>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<map>
#include<arpa/inet.h>
using namespace std;
#define PATH_MSG "./passwd"
//功能1:添加节点(上线成功)
//功能2:删除节点(下线)
//功能3:验证上线
//功能4:判断消息功能
//功能5:注册
//定义结构体:注册
struct reg
{
	char name[10];
	char pwd[10];
};
//定义结构体:
struct msg
{
	char type;//消息类型  L--上线 Q:下线  B:广播消息  C:聊天(私有) 注册R:
	long ilen;//内容的长度
};
//前置声明 
void list(map<string,sockaddr_in> &online);
//保存到文件中
bool saveMsg(struct reg cm)
{
	bool state=false;
//1打开
	int fd=open(PATH_MSG,O_CREAT|O_RDWR,0644);
//2操作
	if(fd<0)
	{
		perror("open fail");
		return state;
	}
	//遍历查找
	struct reg  r;
	state=true;
	while(read(fd,&r,sizeof(r))>0)
	{
		if(strcmp(r.name,cm.name)==0)
		{
			state=false;	
			break;
		}
	}
	//查找不成功:则添加 
	if(state)
	{
		if(write(fd,&cm,sizeof(cm))!=sizeof(cm))
			state=false;
	}
//3关闭
	close(fd);
	return state;
}
//注册函数
void reg(int sock,struct sockaddr_in caddr)
{
	//接收客户端发送的注册信息
	struct reg r;
	if(recv(sock,&r,sizeof(r),0)==sizeof(r))
	{
		if(saveMsg(r))
		{
			sendto( 
			sock,"ok",2,0,\
		       (sockaddr*)&caddr,\
		       sizeof(caddr)
		      );	
		}
	}
}
//验证---上线之前必须验证
bool check(struct reg m)
{
	bool state=false;
//1对文件遍历
	int fd=open(PATH_MSG,O_RDONLY);
	if(fd<0)//打开失败
		return state;
	struct reg r;
	while(read(fd,&r,sizeof(r))>0)
	{
		if(!strcmp(r.name,m.name) && !strcmp(r.pwd,m.pwd))
		{
			state=true;
			break;
		}
	}
//3关闭文件
	close(fd);
	return state;		
}
//上线
bool addOnline(struct reg m,struct sockaddr_in caddr,int sock,map<string,sockaddr_in> &online)
{
	bool state=false;
	//判断验证是否通过
	if(check(m))
	{
		//将数据插入到在线列表中
		online.insert(pair<string,struct sockaddr_in> (string(m.name),caddr));
		//返回信息
		sendto(sock,"ok",2,0,(sockaddr*)&caddr,sizeof(caddr));
		state=true;
	}
	//临时打印在线人数
	cout<<"在线人数:"<<online.size()<<endl;
	//显示
	list(online);

	return state;
}
//显示在线列表:
void list(map<string,sockaddr_in> &online)
{
	map<string,sockaddr_in> ::iterator it;
	it=online.begin();
	while(it!=online.end())
	{
		cout<<"在线:"<<it->first<<endl;
		it++;
	}
}
int main()
{
//1创建套接字
	int sock=-1,pid=-1;
	sock=socket(AF_INET,SOCK_DGRAM,0);	
	if(sock<0)
	{
		perror("socket fail");
		return -1;
	}
//2绑定套接字
	struct sockaddr_in addr;
	addr.sin_family		=AF_INET;	//地址类型
	addr.sin_port		=htons(7979);	//端口
	addr.sin_addr.s_addr	=INADDR_ANY;	//本机地址
	if(bind(sock,(struct sockaddr*)&addr,sizeof(addr))<0)
	{
		perror("bind error");
		return -1;
	}
//4创建子进程
	pid=fork();
	if(pid>0)//父进程--接收消息(并处理)
	{
		struct msg m; //type=L ilen=20  3="abc"
		int ilen;
		struct sockaddr_in caddr;
		//关联容器---在线列表
		map<string,struct sockaddr_in> online;
		socklen_t clen=sizeof(caddr);
		while(1) 
		{
			//接收内容:不一定此msg的内容  abc  
			ilen=recvfrom( 					\
				      sock,&m,sizeof(m),0,		\
				      (struct sockaddr*)&caddr,&clen 	\
				      );
			if(ilen<0)//网络出问题
			{
				perror("recvfrom fail");
				break;
			}
			else if(ilen!=sizeof(m))
				continue;
			//判断消息的类型
			switch(m.type)
			{
				case 'L'://上线
				{
					cout<<"上线"<<endl;
					//接收发送的验证信息
					struct reg r;
					if(recv(sock,&r,sizeof(r),0)==sizeof(r))
					{
						addOnline(r,caddr,sock,online);
					}
				}
				break;
				case 'Q'://下线
					cout<<"下线"<<endl;
				break;
				case 'B'://广播
					cout<<"广播"<<endl;
				break;
				case 'C'://私信
					cout<<"私信"<<endl;
				break;
				case 'R'://注册
				{
					cout<<"注册"<<endl;
					//注册函数
					reg(sock,caddr);
				}
				break;
				default:  ;
			}
		}
	}	
	else if(pid==0)//子进程
	{
	}
	else 
	{
		perror("fork fail");
		return -1;
	}
//4关闭套接字
	close(sock);
}

   实现客户端向服务器发送消息 :

#include<iostream>
#include<sys/wait.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
using namespace std;
struct reg
{
	char name[10];
	char pwd[10];
};
struct msg
{
	char type;
	long ilen;
};
int main()
{
//1创建套接字
	int sock=socket(AF_INET,SOCK_DGRAM,0);
	int pid;
	pid=fork();
	if(pid>0)
	{
	//2发送  msg
		struct sockaddr_in addr;
		addr.sin_family		=AF_INET;
		addr.sin_port		=htons(7979);
		addr.sin_addr.s_addr	=inet_addr("127.0.0.1");
		//发送注册信息
		struct msg m={'L',10};	    //将L 改为 R 则为注册
		sendto(sock,&m,sizeof(m),0,(struct sockaddr*)&addr,sizeof(addr));
		struct reg r={"lxw","123456"};
		sendto(sock,&r,sizeof(r),0,(struct sockaddr*)&addr,sizeof(addr));
		//等待子进程结束 
		wait(NULL);
	}
	else if(pid==0)
	{
		char buf[100]="";
		int ilen=0;
		while((ilen=recv(sock,buf,100,0))>0)
		{
			buf[ilen]='\0';
			cout<<buf<<endl;
		}
	}
//3关闭
	close(sock);
}

   在上面的基础上 服务器实现注册 , 上线 , 下线 , 私聊 的协议功能 : 

#include<iostream>
#include<sys/wait.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
using namespace std;
//注册信息
struct reg
{
	char name[10];
	char pwd[10];
};
//消息类型
struct msg
{
	char type;
	long ilen;
};
struct chart
{
	char name[10];		//目的名
	char content[100];
};
int main()
{
//1创建套接字
	int sock=socket(AF_INET,SOCK_DGRAM,0);
	int pid;
	pid=fork();
	if(pid>0)
	{
//2发送 msg
	struct sockaddr_in addr;
	addr.sin_family			=AF_INET;
	addr.sin_port			=htons(7979);
	addr.sin_addr.s_addr		=inet_addr("192.168.8.209");

	//发送注册信息
	//struct msg m={'L',10};
	//sendto(sock,&m,sizeof(m),0,(struct sockaddr*)&addr,sizeof(addr));
	//struct reg r={"lxw","123456"};
	//sendto(sock,&r,sizeof(r),0,(struct sockaddr*)&addr,sizeof(addr));
	struct msg m1={'C',110};
	sendto(sock,&m1,sizeof(m1),0,(struct sockaddr*)&addr,sizeof(addr));
	//char name[10]="lxw";
	//struct reg r1={"lxw","123456"};
	//sendto(sock,&r1,sizeof(r1),0,(struct sockaddr*)&addr,sizeof(addr));
	struct chart ct={"lxw","你好阿!"};
	sendto(sock,&ct,sizeof(ct),0,(struct sockaddr*)&addr,sizeof(addr));

	wait(NULL);
	}
	else if(pid==0)
	{
		char buf[100]="";
		int ilen=0;
		while((ilen=recv(sock,buf,100,0))>0)
		{
			buf[ilen]='\0';
			cout<<buf<<endl;
		}
	}
//关闭
	close(sock);
}

   同样的客户端的实现 : 

#include<iostream>
#include<sys/wait.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
using namespace std;
//注册信息
struct reg
{
	char name[10];
	char pwd[10];
};
//消息类型
struct msg
{
	char type;
	long ilen;
};
struct chart
{
	char name[10];		//目的名
	char content[100];
};

int main()
{
//1创建套接字
	int sock=socket(AF_INET,SOCK_DGRAM,0);
	int pid;
	pid=fork();
	if(pid>0)
	{
//2发送 msg
	struct sockaddr_in addr;
	addr.sin_family			=AF_INET;
	addr.sin_port			=htons(7979);
	addr.sin_addr.s_addr		=inet_addr("192.168.8.209");

	//发送注册信息
	//struct msg m={'L',10};
	//sendto(sock,&m,sizeof(m),0,(struct sockaddr*)&addr,sizeof(addr));
	//struct reg r={"lxw","123456"};
	//sendto(sock,&r,sizeof(r),0,(struct sockaddr*)&addr,sizeof(addr));
	struct msg m1={'C',110};
	sendto(sock,&m1,sizeof(m1),0,(struct sockaddr*)&addr,sizeof(addr));
	//char name[10]="lxw";
	//struct reg r1={"lxw","123456"};
	//sendto(sock,&r1,sizeof(r1),0,(struct sockaddr*)&addr,sizeof(addr));
	struct chart ct={"lxw","你好阿!"};
	sendto(sock,&ct,sizeof(ct),0,(struct sockaddr*)&addr,sizeof(addr));

	wait(NULL);
	}
	else if(pid==0)
	{
		char buf[100]="";
		int ilen=0;
		while((ilen=recv(sock,buf,100,0))>0)
		{
			buf[ilen]='\0';
			cout<<buf<<endl;
		}
	}
//关闭
	close(sock);
}

猜你喜欢

转载自blog.csdn.net/Superman___007/article/details/82928836
今日推荐