服務端客戶端通訊,註冊,上線,下線,私聊,廣播(UDP)
阿新 • • 發佈:2018-11-22
框架: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);
}