思维导图
基于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;
}