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

📄 scd.c

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


#define QLEN 32

char *  getoptarg = "im:p:";
char *	ProgramName = "SCD";
char *  version = "0.1";
int	port = 7006;

/*print the usage of scc*/
static void usage(char *msg)
{
        fprintf(stderr, "%s: usage error: %s\n", ProgramName, msg);
        fprintf(stderr, "usage:\t%s [-i] [-p port] [-m max]\n", ProgramName);
        fprintf(stderr, "\t-i\tencryption is disable.\n");
        fprintf(stderr, "\t-p port\tcause port to be used as the port to bind.\n");
	fprintf(stderr, "\t       \tthe default value is 6667.\n");
        fprintf(stderr, "\t-m max\thow many clients may connect to scd at a time.\n");
	fprintf(stderr, "\t      \tthe default value is 500\n");
        exit(0);
}


/*handle the command line arguments*/
static void parse_args(int argc,char **argv)
{
        int  argch;
        while ((argch = getopt(argc, argv, getoptarg)) != EOF) {
                switch (argch) {
                        case 'm':
				/*the max number of user*/
				max_user = atoi(optarg);
                                break;
                        case 'i':
				fprintf(stderr,"encryption disable.\n");
                                break;
                        case 'p':
				/*the port used as the port to bind*/
				port = atoi(optarg);
                                break;
                        default:
                                usage("unrecognized option");
                }
        }
}


int get_word(FILE * fp,char * name)
{
	int c;
	int i = 0;
	while((c = fgetc(fp)) != EOF
		&& c != '\n')
		name[i++] = c;
	if(c == EOF)
		return 0;
	name[i] = '\0';
	return 1;
}


/*load the information about the user
 * already registered*/
void load_user()
{
	FILE * fp;
	char temp[MAX_NAME];
	char * user_name;
	int length;
	if((fp = fopen(LOG_FILE,"r"))==NULL) {
		if((fp=fopen(LOG_FILE,"w+"))==NULL) {
			log_err("log file open fail!\n");
		}
	}
	while(get_word(fp,temp)) {
		length = strlen(temp)+2;
		user_name = (char *)malloc(sizeof(char)*length);
		if(user_name == NULL) {
			log_err("malloc fail!\n");
		}
		strncpy(user_name,temp,length);
		hash_insert(user_name);
	}
}

/*used to debug the program*/
void print_l()
{
	int i;
	bucket_list p;

	for(i = 0; i < SIZE; i++) {
		p = hash_table[i];
		while(p) {
			fprintf(stderr,"%s,%d\n",p->name,p->connfd);
			p = p->next;
		}
	}
	fprintf(stderr,"\n");
}

void print_a()
{
	int i;
	addr_list p;

	for(i = 0; i < SIZE; i++) {
		p = addr_table[i];
		while(p) {
			fprintf(stderr,"%s,%d\n",p->name,p->connfd);
			p = p->next;
		}
	}
	fprintf(stderr,"\n");
}


int passivesock(const char *transport, int qlen) 
{
	struct servent    * pse;    /* pointer to service information entry */
	struct protoent *ppe;      /* pointer to protocol information entry*/
	struct sockaddr_in sin;    
	int   s, type; 
	char * service = "scd";
	char error[MAX_ERR];
	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;

	sin.sin_port = port;
	/* Map protocol name to protocol number */
	if ( (ppe = getprotobyname(transport)) == 0)
	      fprintf(stderr,"can't get \"%s\" protocol entry\n", transport);
	/* Use protocol to choose a socket type */
	if (strcmp(transport, "udp") == 0) type = SOCK_DGRAM;
	else type = SOCK_STREAM;
	/* Allocate a socket */
	s = socket(PF_INET, type, ppe->p_proto);
	if (s < 0) { 
		sprintf(error,"can't create socket: %s\n", strerror(errno));
		log_err(error);
	}
	/* Bind the socket */
	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
	      sprintf(error,"can't bind to %s port: %s\n", service,strerror(errno));
	      log_err(error);
	}
	if (type == SOCK_STREAM && listen(s, qlen) < 0) {
	      sprintf(error,"can't listen on %s port: %s\n", service,strerror(errno));
	      log_err(error);
	}
	return s;
}


/*initialize the mutexes*/
void init_mutex()
{
	int res;
	if((res=pthread_mutex_init(&num_mutex,NULL))!=0) {
		log_err("mutex init fail!\n");
	}
	if((res=pthread_mutex_init(&addr_mutex,NULL))!=0) {
		log_err("mutex init fail!\n");
	}
	if((res=pthread_mutex_init(&name_mutex,NULL))!=0) {
		log_err("mutex init fail!\n");
	}
	if((res=pthread_mutex_init(&host_mutex,NULL))!=0) {
		log_err("mutex init fail!\n");
	}
}

/*version handshake*/
void version_mes(int connfd)
{
	char temp[MAX_VERSION];
	sprintf(temp,"SCD Version: %s",version);
	send_mes(temp,connfd);
}


/*record the host name into the link list*/
void host_insert(int connfd,char *host)
{
	host_list * temp;
	temp = (host_list *)malloc(sizeof(host_list));
	if(temp == NULL) {
		log_err("malloc fail!\n");
	}
	temp->connfd = connfd;
	temp->host = host;

	pthread_mutex_lock(&host_mutex);
	if(host_tail == NULL) {
		host_head = temp;
		host_tail = temp;
	} else {
		host_tail->next = temp;
		temp->next = NULL;
	}
	pthread_mutex_unlock(&host_mutex);
}



/*delete the host name from the link list*/
host_list * host_delete(int connfd)
{
	host_list * p1;
	host_list * p2;
	int ok = 0;

	pthread_mutex_lock(&host_mutex);
	p1 = host_head;
	p2 = host_head;
	while(p2) {
		if(p2->connfd == connfd) {
			ok = 1;
			break;
		}
		p1 = p2;
		p2 = p2->next;
	}
	if(ok) {
		if(host_head == host_tail) {
			host_head = NULL;
			host_tail = NULL;
		} else if(p2 == host_head) {
			host_head = host_head->next;
		} else if(p2 == host_tail) {
			host_tail = p1;
			p1->next = NULL;
		} else
			p1->next = p2->next;
	}
	pthread_mutex_unlock(&host_mutex);
	if(ok) return p2;
	else   return NULL; 
}


/*let the program to become a daemon program*/
int daemon_init()
{
        pid_t pid;

        if( (pid = fork()) < 0)
                return -1;
        else if(pid != 0) /* parent exit */
                exit(0);

        setsid();
        umask(0);
        /* close stdin, stdout and stderr*/
        freopen("/dev/null", "r", stdin);
        freopen("/dev/null", "w", stdout);
        freopen("/dev/null", "w", stderr);
        return 0;
}

void log_err(char * message)
{
	FILE * fp;

#ifdef Debug
	fprintf(stderr,"%s\n",message);
#else
	if((fp = fopen(LOG_ERR,"w")) == NULL) {
		exit(1);
	}
	fprintf(fp,"%s\n",message);
	fclose(fp);
#endif
	exit(1);
}

int main(int argc,char **argv)
{
	int i;
	int res;
	pthread_t tid;
	pthread_attr_t thread_attr;
	struct sockaddr_in fsin;
	unsigned int alen;
	int msock;
	int ssock;
	char error[MAX_ERR];
	char temphost[MAX_HOST];
	char * host;

	parse_args(argc,argv);
	daemon_init();
	init_mutex();
#ifdef Debug
	fprintf(stderr,"max: %d\n",max_user);
	fprintf(stderr,"port: %d\n",port);
#endif
	init_hash_tab();
	load_user();
	msock = passivesock("tcp", QLEN);

	if((res=pthread_attr_init(&thread_attr)) != 0) {
		log_err("Attribute creation fails!\n");
	}
	if((res=pthread_attr_setdetachstate(&thread_attr,
	    PTHREAD_CREATE_DETACHED)) != 0) {
		log_err("Seting detach attribute fails!\n");
	}
	while (1) {
		alen = sizeof(fsin);
		ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
		if (ssock < 0) {
		       if (errno == EINTR)        continue;
		       //fprintf(stderr,"accept: %s\n", strerror(errno));
		}

		/*check the max number of connect user*/
		pthread_mutex_lock(&num_mutex);
		if(on_line_num == max_user) {
			pthread_mutex_unlock(&num_mutex);
			sprintf(error,"ERR: 104");
			send_mes(error,ssock);
			continue;
		} else {
			on_line_num++;
			pthread_mutex_unlock(&num_mutex);
			version_mes(ssock);
		}

		inet_ntop(AF_INET,&fsin.sin_addr,temphost,sizeof(temphost));
		host = (char *)malloc((strlen(temphost)+2)*sizeof(char));
		if(host == NULL) {
			log_err("malloc fail!\n");
		}
		strcpy(host,temphost);
		host_insert(ssock,host);
		if((res=pthread_create(&tid,&thread_attr,(void * (*)(void *))receive_mes, (void *)ssock)) != 0) {
			log_err("Creating thread fail!\n");
		}
	}
}

⌨️ 快捷键说明

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