⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 message.c

📁 在linux系统下实现了一个多人聊天工具的服务器端和客户端。该工具支持显示在线用户
💻 C
字号:
#include "global.h"


/*write the information of registered users
 * into a file*/
void log_user()
{
	int i;
	FILE * fp;
	bucket_list p;

	if((fp = fopen(LOG_FILE,"w"))==NULL) {
		log_err("open log file fail.\n");
	}
	for(i = 0; i < SIZE; i++) {
		p = hash_table[i];
		while(p) {
			fprintf(fp,"%s\n",p->name);
			p = p->next;
		}
	}
	fclose(fp);
}



/*divide the string received into
 * several parts*/
int divide_mes(char * mes,char * str)
{
	int i = 0;
	int j = 0;
	int k = 0;
	int n;
	int connfd;

	n = sscanf(str,"%d,",&connfd);
	if(n < 1) {
		return -1;
	}

	/*skip the length of the message*/
	while(str[i] && str[i]!=',')
		i++;
	i++;
	/*skip the blank and tab*/
	while(str[i] && (str[i]==' '||str[i]=='\t'))
		i++;
	/*get the content of the message*/
	while(str[i]) mes[k++] = str[i++];
	mes[k] = '\0';
	return connfd;
}


/*delete the user from the hash table*/
void do_quit(int connfd)
{
        int h = hash_int(connfd);
	char * name;
	bucket_list l;
        addr_list a1;
	addr_list a2;

	pthread_mutex_lock(&addr_mutex);
	a1 = addr_table[h];
	a2 = a1;
        while((a2 != NULL) && (a2->connfd != connfd)) {
		a1 = a2;
                a2 = a2->next;
	}
	if(!a1) {
		pthread_mutex_unlock(&addr_mutex);
		return;
	}
	else if(a1 == a2)
		addr_table[h] = a1->next;
	else
		a1->next = a2->next;
	close(a2->connfd);
	pthread_mutex_lock(&name_mutex);
	l = hash_lookup(a2->name);
	if(l)
		l->connfd = -1;
#ifdef Debug
	print_l();
#endif
	pthread_mutex_unlock(&name_mutex);
	a2->name = NULL;
	free(a2);
#ifdef Debug
	print_a();
#endif
	pthread_mutex_unlock(&addr_mutex);
	pthread_mutex_lock(&num_mutex);
	on_line_num--;
	pthread_mutex_unlock(&num_mutex);
}


/*send the message to the specified user*/
void do_sent_by_name(char * mes,int connfd)
{
	int i = 0;
	int j = 0;
	int b;
	int fd;
	char name[MAX_NAME];
	char sname[MAX_NAME];
	char error[MAX_ERR];
	bucket_list l;
	addr_list a;

	while(mes[i]==' '||mes[i]=='\t')
		i++;
	/*get the user name that the user
	 * want the message to send to*/
	while(mes[i]&&mes[i]!='\n'&&j<MAX_NAME&&
	      mes[i]!=' ' &&mes[i]!='\t')
		name[j++] = mes[i++];
	name[j] = '\0';
	if(j == 0)
		return;
	while(mes[i]=='\n'||mes[i]==' '||
	      mes[i]=='\t')
		i++;

	pthread_mutex_lock(&addr_mutex);
	a = addr_lookup(connfd);
	if(a == NULL||a->name == NULL) {
		pthread_mutex_unlock(&addr_mutex);
		return;
	}
	else {
		strcpy(sname,a->name);
	}
	pthread_mutex_unlock(&addr_mutex);

	pthread_mutex_lock(&name_mutex);
	l = hash_lookup(name);
	if(l == NULL) {
		b = 0;
	} else {
		if(l->connfd == -1)
			b = 1;
		else {
			fd = l->connfd;
			b = 2;
		}
	}
	pthread_mutex_unlock(&name_mutex);
	switch(b) {
		case 0:
		case 1:
			sprintf(error,"ERR: 103");
			send_mes(error,connfd);
			break;
		case 2:
			send_name_mes(&mes[i],sname,fd);
			send_name_mes(&mes[i],sname,connfd);
			break;
		default:
			break;
	}
}

/*send the user on line to the command sender*/
void do_who(int connfd)
{
	int i;
	char temp[MAX_MES];
	addr_list a;

	temp[0] = '\0';
	pthread_mutex_lock(&addr_mutex);
	for(i = 0; i < SIZE; i++) {
		a = addr_table[i];
		while(a) {
			if(a->name != NULL) {
				strcat(temp,a->name);
				strcat(temp,"@");
				strcat(temp,a->host);
				strcat(temp," ");
			}
			a = a->next;
		}
	}
	pthread_mutex_unlock(&addr_mutex);
	send_mes(temp,connfd);
}



void do_help(int connfd)
{
	char help1[] = "/log filename\n  This command causes scc to log all input to the\n  file filename and display it on the terminal. If no\n  filename is given,scc.log will be used.\n/quit\n  cause the client to terminate the connection.\n";
	char help2[] = "/m nickname message\n  sent the message only to \"nickname\"\n/nick nickname\n  let the user to change its nickname to \"nickname\"\n/who\n  to send the list of on line clients to the requester\n/help\n  send the available commands to the requester\n";

	send_mes(help1,connfd);
	send_mes(help2,connfd);
}


/*change the nick name*/
void do_change_name(char * mes,int connfd)
{
	int i = 0;
	int j = 0;
	char newname[MAX_NAME];
	char error[MAX_ERR];
	char * nn;
	addr_list a;
	bucket_list l1;
	bucket_list l2;

	while(mes[i]==' '||mes[i]=='\t')
		i++;
	while(mes[i]&&mes[i]!='\n'&&j<MAX_NAME&&
	      mes[i]!=' ' &&mes[i]!='\t')
		newname[j++] = mes[i++];
	if(j == MAX_NAME) {
		sprintf(error,"server: new name is too long!");
		send_mes(error,connfd);
		return;
	}
	newname[j] = '\0';
	nn = (char *)malloc(sizeof(char)*(strlen(newname)+2));
	if(!nn) {
		log_err("malloc fail!");
	}
	strcpy(nn,newname);

	pthread_mutex_lock(&addr_mutex);
	pthread_mutex_lock(&name_mutex);
	l1 = hash_lookup(newname);
	a = addr_lookup(connfd);
	l2 = hash_lookup(a->name);
	/*the name already used*/
	if(l1&&l1->connfd >= 0) {
		sprintf(error,"server: the name is already used by another user!");
		send_mes(error,connfd);
		pthread_mutex_unlock(&name_mutex);
		pthread_mutex_unlock(&addr_mutex);
		return;
	/*change user*/
	} else if(l1&&l1->connfd < 0) {
		l1->connfd = connfd;
		l2->connfd = -1;
		a->name = l1->name;
		free(nn);
	/*change the user name */
	} else {
		free(l2->name);
		l2->name = nn;
		a->name = nn;
	}
#ifdef Debug
	print_a();
	print_l();
#endif
	log_user();
	pthread_mutex_unlock(&name_mutex);
	pthread_mutex_unlock(&addr_mutex);
}

/*classify the message into several types
 * 1 stand for "send nickname"
 * 2 stand for control message
 * 3 stand for normal message*/
int classify_mes(char * mes,int connfd)
{
	int i = 0;
	int j = 0;
	int len = 0;
	//char temp[MAX_MES];
	//receive_mes(temp,connfd);


	if(mes[0] == '/')
		return 2;
	else if(strncmp(mes,"SCC Version:",12)==0)
		return 4;
	else if(strncmp(mes,"nickname:",9)==0)
		return 1;
	else
		return 3;
}

/*case 1*/
/*the client send its nickname to the server
 * max user check and nickname in used check
 * are do here,also version handshake do here*/
void nickname_mes(char * mes,int connfd)
{
	int i = 0;
	int j = 0;
	int b;
	char addname[MAX_NAME];
	char error[MAX_ERR];
	char temp[MAX_MES];
	char * name;
	host_list * h;
	bucket_list l;
	addr_list a;
	

	i += 9;
	/*skip blank and tab*/
	while(mes[i]==' '||mes[i]=='\t')
		i++;
	/*record the message*/
	while(mes[i]!='\0'&&j<MAX_NAME)
		addname[j++] = mes[i++];
	addname[j] = '\0';

	if(j == 0)
		return;
	/*nickname too long*/
	else if(j == MAX_NAME) {
		sprintf(temp,"server: nickname too long.");
		send_mes(temp,connfd);
		return;
	}

	h = host_delete(connfd);
	pthread_mutex_lock(&addr_mutex);
	pthread_mutex_lock(&name_mutex);
	/*look up the name in the hash table*/
	l = hash_lookup(addname);
	/*if the name already in the table*/
	if(l) {
		/*the name is in use*/
		if(l->connfd >= 0) {
			pthread_mutex_unlock(&name_mutex);
			pthread_mutex_unlock(&addr_mutex);
			pthread_mutex_lock(&num_mutex);
			on_line_num--;
			pthread_mutex_unlock(&num_mutex);
			free(h->host);
			free(h);
			sprintf(error,"ERR: 101");
			send_mes(error,connfd);
			return;
		} else {
			l->connfd = connfd;
			a = addr_insert(connfd);
			a->name = l->name;
			a->host = h->host;
			free(h);
		}
	} else {/*the name is not in the table*/
		name=(char *)malloc((strlen(addname)+2)*sizeof(char));
		if(name == NULL) {
			pthread_mutex_unlock(&name_mutex);
			pthread_mutex_unlock(&addr_mutex);
			log_err("malloc fail!");
		}
		strcpy(name,addname);
		l = hash_insert(name);
		a = addr_insert(connfd);
		l->connfd = connfd;
		a->name = l->name;
		a->connfd = connfd;
		a->host = h->host;
		free(h);
	}
#ifdef Debug
	print_a();
	print_l();
#endif
	log_user();
	pthread_mutex_unlock(&name_mutex);
	pthread_mutex_unlock(&addr_mutex);
}


/*case 3*/
/*send the message to all the user connected
 * to the server*/
void message_mes(char * mes,int connfd)
{
	int i;
	addr_list a1;
	addr_list a2;

	pthread_mutex_lock(&addr_mutex);
	a2 = addr_lookup(connfd);
	if(!a2||!a2->name) {
		pthread_mutex_unlock(&addr_mutex);
		return;
	}
	for(i = 0; i < SIZE; i++) {
		a1 = addr_table[i];
		while(a1) {
			if(a1->name != NULL)
				send_name_mes(mes,a2->name,a1->connfd);
			a1 = a1->next;
		}
	}
	pthread_mutex_unlock(&addr_mutex);
}


/*case 2*/
/*handle the control message*/
void control_mes(char * mes,int connfd)
{
	int i = 0;
	char error[MAX_ERR];

	if(strncmp(&mes[i],"/m",2)==0) {
		do_sent_by_name(&mes[i+2],connfd);
	} else if(strncmp(&mes[i],"/who",4)==0) {
		do_who(connfd);
	} else if(strncmp(&mes[i],"/nick",5)==0) {
		do_change_name(&mes[i+5],connfd);
	} else if(strncmp(&mes[i],"/help",5)==0) {
		do_help(connfd);
	} else if(strncmp(&mes[i],"/quit",5)==0) {
		do_quit(connfd);
	} else {
		sprintf(error,"ERR: 102");
		send_mes(error,connfd);
	}
}

/*handle all kinds of message here*/
void handle_mes(char * str)
{
	int b;
	int t,n;
	int connfd,len = 0;
	//char mes1[MAX_MES];
	char mes2[MAX_MES];
	char error[MAX_ERR];

	len = strlen(str);
	if(len < 2||len>MAX_MES)
		return;
	if((connfd = divide_mes(mes2,str)) < 0)
		return;
	free(str);

	t = classify_mes(mes2,connfd);
	switch(t) {
		case 1:
			nickname_mes(mes2,connfd);
			break;
		case 2:
			control_mes(mes2,connfd);
			break;
		case 3:
			message_mes(mes2,connfd);
			break;
		default:
			return;
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -