UDP 聊天室實現 經典錯誤

//服務器端
#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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章