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

📄 scc.c

📁 在linux系统下实现了一个多人聊天工具的服务器端和客户端。该工具支持显示在线用户
💻 C
字号:
#include <pwd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>

#include "global.h"

char *getoptarg = "h:ip:n:";
char *ProgramName = "SCC";
char	host[MAXHOST];
char	nickname[MAXNAME];
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 [-h hostname] [-i] [-p port] [-n nickname]\n", ProgramName);
        fprintf(stderr, "\t-h hostname\thostname is the server to connect to.\n");
	fprintf(stderr, "\t           \tthe default value is the localhost.\n");
        fprintf(stderr, "\t-i\tencryption is disable.\n");
        fprintf(stderr, "\t-p port\tcause port to be used to connect to on the server.\n");
	fprintf(stderr, "\t       \tthe default value is the 6667.\n");
        fprintf(stderr, "\t-n nickname\tlogin as nickname on the specified host.\n");
	fprintf(stderr, "\t           \tthe default value is the login name of the user.\n");
        exit(0);
}

/*get the user name of the user*/
void get_user_name(char * nickname)
{
	struct passwd *pw;
	char * User;
        /* get the user id */
        if (!(pw = getpwuid(getuid()))) {
                fprintf(stderr, "%s: your UID isn't in the passwd file.\n",
                        ProgramName);
                exit(1);
        }
        /* dup the user id*/
	if(strlen(pw->pw_name) > MAXHOST*sizeof(char)) {
		fprintf(stderr,"Host name is too long.\n");
		exit(1);
	}
	strncpy(nickname,pw->pw_name,MAXNAME);
        endpwent();
}

/*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 'h':
				/*the host name is too long*/
				if(strlen(optarg) > MAXHOST) {
					fprintf(stderr,"Host name is too long.\n");
					exit(1);
				}
				strncpy(host,optarg,MAXHOST);
                                break;
                        case 'i':
				fprintf(stderr,"encryption disable.\n");
                                break;
                        case 'p':
				port = atoi(optarg);
                                break;
                        case 'n':
				/*the nickname is too long*/
				if(strlen(optarg) > MAXNAME) {
					fprintf(stderr,"Nickname is too long.\n");
					exit(1);
				}
				strncpy(nickname,optarg,MAXNAME);
                                break;
                        default:
                                usage("unrecognized option");
                }
        }
}



int connectsock(const char *transport )
{
	struct hostent *phe;       /* pointer to host information entry     */
	struct servent *pse;       /* pointer to service information entry */
	struct protoent *ppe;      /* pointer to protocol information entry*/
	struct sockaddr_in sin;    /* an Internet endpoint address*/
	int   s, type; /* socket descriptor and socket type       */
	char *service = "scc";
	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;

	sin.sin_port = port;
	/* Map host name to IP address, allowing for dotted decimal */
	if ( phe = gethostbyname(host) )
	      memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
	else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE ) {
	      fprintf(stderr,"can't get \"%s\" host entry\n", host);
	      exit(1);
	}
	/* Map transport protocol name to protocol number */
	if ( (ppe = getprotobyname(transport)) == 0) {
	      fprintf(stderr,"can't get \"%s\" protocol entry\n", transport);
	      exit(1);
	}
	/* 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) {
		fprintf(stderr,"can't create socket: %s\n",strerror(errno));
		exit(1);
	}
	/* Connect the socket */
	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
		     fprintf(stderr,"can't connect to %s.%s: %s\n", host, service,strerror(errno));
		     exit(1);
	}
	return s;
}


/*handle version handshake here and handle
 * too many users error here*/
void handshake(int sevfd)
{
	char temp[MAX_MES];
	char num[20];
	int n,i = 0;
	int len;
	int j = 0;
	int err = 0;
	int k,l;
	char c;
	double scdv = 0;


	/*get the first message*/
	sem_wait(&full);
	sem_wait(&mutex);

	strcpy(temp,mess_buffer[mess_out]);
	mess_out = (mess_out+1)%MAX_SHOW_BUFF;

	sem_post(&mutex);
	sem_post(&empty);

	/*to see whether the message is a handshake message*/
	if(strncmp(temp,"SCD Version:",12)==0) {
		k = 12;
		l = 0;
		while(!isdigit(temp[k]))
			k++;
		while(temp[k]!='\0')
			num[l++] = temp[k++];
		num[l] = '\0';
		scdv = atof(num);
		/*if the server version is lower than 0.2*/
		if(scdv < 0.2) {
			/*ask the user for continue*/
			while(1) {
				fprintf(stderr,"The version of the sever is lower than 0.2. No encryption is provided.\nDo you want to continue?(y/n)\n");
				c = fgetc(stdin);
				if(c == 'y'||c == 'Y')
					break;
				else if(c == 'n'||c == 'N')
					exit(1);
			}
		}
		/*send version message*/
		sprintf(temp,"SCC Version: 0.1");
		send_mes(temp,sevfd);
	} else if(strncmp(temp,"ERR:",4)==0) {
		/*handle errors here*/
		err = get_int(&temp[4]);
		if(err < 0) {
			fprintf(stderr,"unknown error message\n");
		} else if(err == 101) {
			fprintf(stderr,"nickname exists\n");
		} else if(err == 104) {
			fprintf(stderr,"too many users\n");
		} else {
			fprintf(stderr,"unknown error message\n");
		}
		exit(1);
	}
}


/*connect the server*/
/*create two thread one to handle the screen and the other is 
 * to handle the network*/
void TCP_scc()
{
	char * arg1 = "test1";
	char * arg2 = "test2";
	char temp[MAX_MES];
	int res;
	int s;
	pthread_t tid_scr;
	pthread_t tid_net;
	pthread_attr_t thread_attr;
	/*connect here*/
	s = connectsock("tcp");

	serfd = s;

	if((res=pthread_attr_init(&thread_attr)) != 0) {
		fprintf(stderr,"Attribute creation fails!\n");
		exit(1);
	}
	if((res=pthread_attr_setdetachstate(&thread_attr,
	    PTHREAD_CREATE_DETACHED)) != 0) {
		fprintf(stderr,"Seting detach attribute fails!\n");
		exit(1);
	}
	if((res=pthread_create(&tid_net,&thread_attr,(void * (*)(void *))receive_mes, (void *)s)) != 0) {
		fprintf(stderr,"Creating thread fail!\n");
		exit(1);
	}

	handshake(s);
	/*send nickname to the server*/
	sprintf(temp,"nickname: %s",nickname);
	send_mes(temp,s);

	if((res=pthread_create(&tid_scr,NULL/*&thread_attr*/,(void * (*)(void *))thread_screen, NULL)) != 0) {
		fprintf(stderr,"Creating thread fail!\n");
		exit(1);
	}
	pthread_join(tid_scr, NULL);
	(void)pthread_attr_destroy(&thread_attr);
	return;
}

/*initialize the semaphores*/
void init_sem()
{
	int res;
	if((res = sem_init(&full,0,0))!=0) {
		fprintf(stderr,"semaphore initialization fail!\n");
		exit(1);
	}
	if((res = sem_init(&empty,0,MAX_SHOW_BUFF))!=0) {
		fprintf(stderr,"semaphore initialization fail!\n");
		exit(1);
	}
	if((res = sem_init(&mutex,0,1))!=0) {
		fprintf(stderr,"semaphore initialization fail!\n");
		exit(1);
	}
}

int main(int argc,char **argv)
{
	int res;
	get_user_name(nickname);
	strcpy(host,"localhost");
	parse_args(argc,argv);
	init_sem();
	fprintf(stderr,"nickname: %s\n",nickname);
	fprintf(stderr,"host: %s\n",host);
	fprintf(stderr,"port: %d\n",port);
	TCP_scc();
	exit(0);
}

⌨️ 快捷键说明

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