思维导图
基于UDP通信模型的网络聊天室
消息分类及数据包结构
服务器端
#include <head.h>
#define SER_PORT 8888
#define SER_IP "192.168.232.133"
typedef struct mb
{
struct sockaddr_in cin;
char name[20];
struct mb *next;
}*member;
//群发消息
int send_to_all(int sfd,member head,const char *buf,size_t length)
{
member p=head;
while(p!=NULL)
{
sendto(sfd,buf,length,0,(struct sockaddr*)&(p->cin),sizeof(p->cin));
p=p->next;
}
return 0;
}
//增加成员
member add_member(member head,const char *data,struct sockaddr_in cin)
{
member p=(member)malloc(sizeof(struct mb));
p->cin=cin;
strcpy(p->name,data);
p->next=head;
head=p;
return head;
}
//删除成员
member del_member(member head,const char *name_point)
{
member p=head;
if(strcmp(p->name,name_point)==0)
{
head=p->next;
free(p);
p=NULL;
return head;
}
while(strcmp(p->name,name_point)!=0)
{
p=p->next;
}
if(p->next==NULL)
{
member q=head;
while(q->next->next!=NULL)
{
q=q->next;
}
free(p);
p=NULL;
q->next=NULL;
return head;
}
member q=head;
while(strcmp(q->next->name,name_point)!=0)
{
q=q->next;
}
q->next=p->next;
free(p);
p=NULL;
return head;
}
int main(int argc, const char *argv[])
{
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd==-1)
{
perror("socket error:");
return -1;
}
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 error:");
return -1;
}
struct sockaddr_in cin;
socklen_t socklen=sizeof(cin);
printf("bind success\n");
struct pollfd pfd[1024];
pfd[0].fd=0;
pfd[0].events=POLLIN;
pfd[1].fd=sfd;
pfd[1].events=POLLIN;
int n=2;
member head=NULL;
while(1)
{
int res=poll(pfd,n,-1);
if(res==-1)
{
perror("poll error:");
return -1;
}
else if(res==0)
{
printf("manbaout\n");
return -1;
}
if(pfd[0].revents==POLLIN)
{
//系统发送消息
char buf[128]="";
scanf("%s",buf);
char sys_buf[200];
sprintf(sys_buf,"***system***>>>%s",buf);
send_to_all(sfd,head,sys_buf,sizeof(sys_buf));
printf("系统发送消息\n");
}
if(pfd[1].revents==POLLIN)
{
//接收消息
char buf[200]="";
recvfrom(pfd[1].fd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&socklen);
short *type_point = (short*)buf;
switch(ntohs(*type_point))
{
case 1:
{
//接收到登录的消息
char *data_point = buf+2;
char buf[300]="";
sprintf(buf,"**********%s已登录**********",data_point);
send_to_all(sfd,head,buf,sizeof(buf));
head=add_member(head,data_point,cin);
printf("%s登录\n",data_point);
break;
}
case 2:
{
//接收到普通的消息
char *name_point=buf+2;
char *data_point=name_point+strlen(name_point)+1;
char buf[300]="";
sprintf(buf,"%s>>>%s",name_point,data_point);
send_to_all(sfd,head,buf,sizeof(buf));
printf("%s发送消息\n",name_point);
break;
}
case 3:
{
//接收到退出消息
char *name_point=buf+2;
char *data_point=name_point+strlen(name_point)+1;
char endbuf[20]="";
strcpy(endbuf,"quit");
sendto(sfd,endbuf,sizeof(endbuf),0,(struct sockaddr*)&cin,sizeof(cin));
del_member(head,name_point);
char buf[300]="";
sprintf(buf,"**********%s已下线**********",name_point);
send_to_all(sfd,head,buf,sizeof(buf));
printf("%s下线\n",name_point);
break;
}
}
}
}
close(sfd);
return 0;
}
客户端
#include <head.h>
#define SER_PORT 8888
#define SER_IP "192.168.232.133"
int login(int sfd,struct sockaddr_in sin,const char *name)
{
char buf[200]="";
short *type_point = (short*)buf;
char *data_point = buf+2;
*type_point=htons(1);
strcpy(data_point,name);
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
return 0;
}
int main(int argc, const char *argv[])
{
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd==-1)
{
perror("socket error:");
return -1;
}
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(SER_PORT);
sin.sin_addr.s_addr=inet_addr(SER_IP);
socklen_t socklen;
printf("====================欢迎使用网络聊天室====================\n");
printf("请输入姓名:");
char name[20];
scanf("%s",name);
login(sfd,sin,name);
pid_t pid;
pid=fork();
if(pid>0)
{
//父进程,用于发消息
char buf[128]="";
short *type_point = (short*)buf;
char *name_point = buf+2;
strcpy(name_point,name);
char *data_point=name_point+strlen(name_point)+1;
while(1)
{
scanf("%s",data_point);
if(strcmp(data_point,"quit")==0)
{
*type_point=htons(3);
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
break;
}
*type_point=htons(2);
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
}
}
else if(pid==0)
{
//子进程,用于接收消息
while(1)
{
char buf[128];
recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);
if(strcmp(buf,"quit")==0)
{
break;
}
printf("%s\n",buf);
}
}
wait(NULL);
close(sfd);
return 0;
}