版权声明:请在征得作者同意的情况下,可以进行非盈利性引用。引用请注明出处:“作者:慕华思弦 转载地址” 字样,以尊重作者的劳动成果,并保持良好的版权意识。 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);
}