//服務器端 #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);
//XXX
strcpy(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==
42934
liu說:sdasda
:43490
==3==
42934
liu說:sadasda
:43490
==4==
42934
liu說:adasdas
:4