UDP 聊天室实现 经典错误

来源:互联网 发布:vivo软件商店手机版 编辑:程序博客网 时间:2024/05/01 14:59
//服务器端#include "Header.h"typedef struct{char name[10];SA_IN address;}USER;//XXX :用户链表typedef struct Hnode_list{USER data;struct Hnode_list *next;}Hlink,*plink;int  memoryError(plink  p) ;int  creatUserList(plink head);int findUser(plink  head,char name[10]);int delUser(plink  head,char name[10]);int getAllUser(plink const head);int addUser(plink head,USER data);//XXX :用户链表void ProcessLogin(char* command,SA_IN rec_addr);void ProcessChat(char* command);plink head;int main(void){char buf[BUFFERSIZE];SA_IN address, rec_addr;int socket_fd;socklen_t length;head=malloc(sizeof(Hlink));//用户列表头creatUserList(head);//创建列表if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) == -1){perror("套接字创建失败");exit(-1);}memset(&address,0,sizeof(address));address.sin_family = AF_INET;address.sin_addr.s_addr = inet_addr("127.0.0.1");address.sin_port = htons(8000);if(bind(socket_fd,(SA *)&address,sizeof(address)) == -1){perror("套接字绑定失败");exit(-1);}int i=0;length = sizeof(rec_addr);while(1){printf("==%d==\n",i);if(recvfrom(socket_fd,buf,sizeof(buf),0,(SA *)&rec_addr,&length) == -1){perror("接收消息失败");}printf("%hu\n",ntohs(rec_addr.sin_port));switch(buf[0]){case 'L':ProcessLogin(buf,rec_addr);break;case 'C':ProcessChat(buf);break;case 'Q':break;default : printf("ERROR");break;}i++;}close(socket_fd);}void ProcessLogin(char* command,SA_IN rec_addr){int socket_fd;char name[10];char ip[32];char buf[BUFFERSIZE];USER user;strcpy(name,command+1);strcpy(ip,inet_ntoa(rec_addr.sin_addr));if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) == -1){perror("套接字创建失败");exit(-1);}if(findUser(head,name)==-1){strcpy(user.name,name);user.address=rec_addr;addUser(head,user);buf[0]='Y';if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&rec_addr,sizeof(rec_addr))==-1){perror("登录失败");}}else{buf[0]='N';if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&rec_addr,sizeof(rec_addr))==-1){perror("登录失败");}}close(socket_fd);}void ProcessChat(char* command){int socket_fd;char buf[BUFFERSIZE];SA_IN address;if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) == -1){perror("套接字创建失败");exit(-1);}plink p=head->next;while(p!=NULL){address=(p->data).address;sprintf(buf,"%s\n",command+1);//if(strncmp(buf,(p->data).name,strlen((p->data).name))==0)   //屏蔽属于自己的消息//continue;if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&address,sizeof(address))<0){perror("消息发送失败");}printf("%s:%hu\n",buf,ntohs(address.sin_port));p=p->next;}close(socket_fd);}//XXX:使用带头结点的单向链表   存放用户信息int  memoryError(plink  p)  //判断内存是否申请成功{if(p==NULL){  printf("MEMORY ERROR!");  return 1; } return 0;}int  creatUserList(plink head){if(memoryError(head))return -1;head->next=NULL;}int addUser(plink head,USER data)  //始终在表头插入{plink new_create=malloc(sizeof(Hlink));if(memoryError(new_create))return -1;new_create->data=data;new_create->next=head->next;head->next=new_create;}int getAllUser(plink const head){plink p=head->next;while(p!=NULL){printf("%s:%s:%hu\n",(p->data).name,inet_ntoa((p->data).address.sin_addr),ntohs((p->data).address.sin_port));p=p->next;}}int delUser(plink  head,char name[10]){plink q=head;plink p=head->next;while(p!=NULL){if(strcmp((p->data).name,name)==0)break;q=p;p=p->next;}if(p==NULL){printf("删除用户失败\n");return -1;}q->next=p->next;free(p);p=NULL;}int findUser(plink  head,char name[10]){plink p=head->next;while(p!=NULL){if(strcmp((p->data).name,name)==0)return 0;p=p->next;}if(p==NULL)return -1;}//XXX:使用带头结点的单向链表   存放用户信息

//客户端
#include "Header.h"void dispMessage(int signo);void killAll(int signo);char* ProcessLogin(SA_IN serv_addr);pid_t pid;int main(void){signal(SIGUSR1,dispMessage);signal(SIGINT,killAll);int socket_fd;char buf[BUFFERSIZE];char name[10];SA_IN serv_addr;//XXX:服务器配置信息memset(&serv_addr,0,sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");serv_addr.sin_port = htons(8000);//XXXstrcpy(name,ProcessLogin(serv_addr));if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) == -1){perror("套接字创建失败");exit(-1);}if((pid=fork())==-1){perror("子进程创建失败");return -1;}if(pid==0)//子进程{sprintf(buf,"C%s上线了",name); //sendto在此处相当于第一次放送,这跟tcp connect 差不多,会自动分配ip端口号、、错误根源if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&serv_addr,sizeof(serv_addr)) < 0){perror("发送失败");}while(1){pause();if(recvfrom(socket_fd,buf,sizeof(buf),0,NULL,NULL)==-1){perror("接收消息失败");}printf("[收到消息]%s\n",buf);}}char buf_temp[BUFFERSIZE];while(1)//父进程{printf("<请输入>");scanf("%s", buf_temp);sprintf(buf,"C%s说:%s",name,buf_temp);if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&serv_addr,sizeof(serv_addr)) < 0){perror("发送失败");}kill(pid,SIGUSR1);}}//////////////////////////////////////////////Siganl//////////////////////////////////////////////void killAll(int signo){printf("\n%d进程结束\n",getpid());exit(-1);}void dispMessage(int signo){;}//////////////////////////////////////////////Siganl//////////////////////////////////////////////char* ProcessLogin(SA_IN serv_addr){int socket_fd;char buf[BUFFERSIZE];static char name[10];if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) == -1){perror("套接字创建失败");exit(-1);}while(1){printf("请输入用户名:");buf[0]='L';scanf("%s",buf+1);strcpy(name,buf+1);if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&serv_addr,sizeof(serv_addr)) < 0){perror("登录失败");}recvfrom(socket_fd,buf,sizeof(buf),0,NULL,NULL);if(buf[0]=='N'){printf("该用户名已被使用,请重新输入用户名\n");}else if(buf[0]=='Y'){printf("登录成功\n");close(socket_fd);return name;break;}}//printf("==END===\n");}//错误原因
yang@ubuntu:~/Day_33/ChartRoom$ ./Server==0==43490//登陆端口号==1==42934//子进程接受的端口号,不匹配liu上线了:43490==2==42934liu说:sdasda:43490==3==42934liu说:sadasda:43490==4==42934liu说:adasdas:4