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

📄 scd.c

📁 在RedHad9 下实现文字界面的聊天程序。此源码示范了C语言的socket通信编码;RedHad下如何编译c代码。内附说明文档详细说明了socket通信原理和代码解释。
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "scd.h"

//deal with client's request
void process_cli(int connectfd, struct sockaddr_in client);
//when server create a thread ,call this function
void * start_routine(void* arg);
//add a client into a list
int add_client(char cli_name[], int connfd, char hostname[]);
//delete a client from a list
void delete_client(char cli_name[]);
//recongnize the commands or send the common message to other clients
int processInput(char recvbuf[],int connectfd, char cli_name[]);
//send the message to all clients
void all_send(char cli_name[], char msg[]);
//change client's name for the command--"nick nickname"
int changeNickName(char cli_name[], char newname[], int connectfd);
//get all client's name for the command--"/who"
void getAllCli_Name();
//send the message to a special client
int one_send(char* tokenPtr, char cli_name[], char msg[]);
//get all clients who are connected to the server
void sendcli_list(int connectfd);
//check the parameter--"./scd [-i] [-m max] [-p port]"
int checkParam(int argc,char* argv[],int* isSecure,int* backlog,int* port);
//read the help file for command--"/help"
void ReadHelpFile(char cmdbuf[]);
//change a client's passwd for command--"/passwd"
int changePasswd(char cli_name[], char passwd[],int connectfd);

void decrypt(char sendbuf[], char passwd[]);

void mydecrypt(char sendbuf[], char passwd[]);

void myencrypt(char sendbuf[], char passwd[]);


int main(int argc,char * argv[])
{
	int listenfd,connectfd;
	pthread_t thread;
	struct ARG *arg;
	struct sockaddr_in server;
	struct sockaddr_in client;
	int sin_size;
	int opt;
	int isSecure,backlog,port;

	isSecure=1;
	backlog=0;
	port=0;
	
	if(checkParam(argc,argv,&isSecure,&backlog,&port)==0)
	{
		exit(1);
	}
//	printf("isSecure:%d\tbacklog:%d,\tport:%d\n",isSecure,backlog,port);

	if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1)
	{
		perror("Creating socket failed.");
		exit(1);
	}
	
	//设置套接字选项为SO_REUSEADDR,即socket可重用
	opt=SO_REUSEADDR;       
	setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

	bzero(&server,sizeof(server));

	//设置套接字地址
	server.sin_family=AF_INET;
	server.sin_port=htons((port==0)?PORT:port);     
	server.sin_addr.s_addr=htonl(INADDR_ANY);      /*填入本机IP地址*/

	/* 绑定:将套接字和地址信息相关连
	函数原形:int bind(int s,const struct sockaddr * name,int namelength);  */
	if(bind(listenfd,(struct sockaddr*)&server,sizeof(struct sockaddr))==-1)
	{
		perror("Bind error.");
		exit(1);
	}

	/* 监听操作由listen()实现,listenfd是套接字系统调用返回的套接字描述符
	backlog指定在请求队列中等待服务请求的数目进行了限制 */
	if(listen(listenfd,(backlog==0)?BACKLOG:backlog)==-1)  
	{
		perror("listen() error.");   //队列已满,拒绝连接请求
		exit(1);
	}	

	sin_size=sizeof(struct sockaddr_in);
	while(1)
	{
		if((connectfd=accept(listenfd,(struct sockaddr *)&client,&sin_size))==-1)
		{
			perror("accept() error\n");
			exit(1);
		}
	/* 把连接套接字(connectfd)和客户地址信息(client)付给arg */
		arg=malloc(sizeof(struct ARG));
		arg->connfd=connectfd;
		memcpy((void *)&arg->client,&client,sizeof(client));

		if(pthread_create(&thread,NULL,start_routine,(void*)arg))
		{
			perror("Pthread_create() error");
			exit(1);			
		}	
	}
	close(listenfd);
}

void process_cli(int connectfd, struct sockaddr_in client)
{
	int num,i,isCommand;
	char hostname[30];
	char cli_name[MAXDATASIZE], recvbuf[MAXDATASIZE];
	isCommand=0;

	//获取此客户机的IP地址
	strcpy(hostname, inet_ntoa(client.sin_addr));
	printf("You got a connection from %s. ", hostname);

	//接收nickname
	num=recv(connectfd,cli_name,MAXDATASIZE,0);
	if(num==0)
	{
		close(connectfd);
		printf("Client disconnected.\n");
		return;
	}
	cli_name[num]='\0';

	//检验nickname是否已经被用
	while(add_client(cli_name,connectfd,hostname)==0)
	{
		//send(connectfd,errbuf,strlen(errbuf),0);  // send the error message 
		one_send(cli_name,cli_name,errbuf);

		num=recv(connectfd,cli_name,MAXDATASIZE,0);  // get the nickname again !
		if(num==0)
		{
			close(connectfd);
			printf("Client disconnected.\n");
			return;
		}
		cli_name[num-1]='\0';		
	}
	printf("Client's name is %s.\n",cli_name);
	
	//接收客户信息
	while(num=recv(connectfd,recvbuf,MAXDATASIZE,0) )
	{
		recvbuf[num]='\0';

		decrypt(recvbuf,cli_name);	//解密	

		printf("Received client( %s ) message:%s\n",cli_name,recvbuf);

		isCommand = processInput(recvbuf,connectfd,cli_name);  //处理信息里可能有的命令

		if(isCommand ==1 || isCommand==3 || isCommand==4 || isCommand==5 || isCommand==6)
		{
			continue;                  //do not send the command input
		}
		else if(isCommand ==2)                  //get the command----quit
		{
			delete_client(cli_name);
			close(connectfd);
			return;
		}

		all_send(cli_name,recvbuf);           // send this message to all the clients
	}

	//客户已退出,所以删除此用户,并关闭连接
	delete_client(cli_name);
	close(connectfd);
}

void * start_routine(void * arg)
{
	struct ARG *info;
	info=(struct ARG *)arg;
		
	process_cli(info->connfd,info->client);   //处理此客户请求

	free(arg);
	pthread_exit(NULL);   //结束本线程
}

//*************************************



int add_client(char cli_name[] , int connfd, char hostname[])
{
	struct clientsInfo* a_client ;
	struct clientsInfo* pcli;

	pthread_mutex_lock(&a_mutex);   //加锁
	a_client = (struct clientsInfo*)malloc(sizeof(struct clientsInfo));
	if(!a_client)
	{
		fprintf(stderr,"add_request: out of memory\n");
		return 0;
	}
	memcpy(a_client->nickname,cli_name,NAMESIZE);
	strcpy(a_client->hostname,hostname);
	a_client->connectfd=connfd;
	a_client->next = NULL;

	if(clientsCount==0)
	{
		clients=a_client;
		last_client=a_client;
	}
	else
	{
		pcli = clients;
		while(pcli != NULL)           // tranverse the list to make sure that no two nickname is the same
		{
			if(!strcmp(pcli->nickname,a_client->nickname))
			{
				pthread_mutex_unlock(&a_mutex);  //解锁
				return 0;
			}
			pcli = pcli->next;
		}
		last_client->next=a_client;
		last_client = a_client;
	}
	clientsCount++;
	pthread_mutex_unlock(&a_mutex); //解锁
	return 1;
}
	
	
void delete_client(char cli_name[])
{
	struct clientsInfo* pcli1;
	struct clientsInfo* pcli2;

	pthread_mutex_lock(&a_mutex);  //加锁

	if(clientsCount > 0)
	{		
		pcli1 = clients;
		pcli2 = clients;
		if(!strcmp(pcli1->nickname,cli_name))  //find it in the first place
		{
			clients = clients->next;			
			if(last_client==NULL)
			{
				last_client = NULL;
			}
			clientsCount--;
			pthread_mutex_unlock(&a_mutex);  //解锁
			return;
		}
		pcli1=pcli1->next;
		while(pcli1 != NULL)           // tranverse the list to find to nickname to delete
		{
			if(!strcmp(pcli1->nickname,cli_name))  //find it
			{
				pcli2->next=pcli1->next;
				free(pcli1);
				pcli1=pcli2->next;
				if(last_client==NULL)
				{
					last_client = NULL;
				}
				clientsCount--;
				pthread_mutex_unlock(&a_mutex);  //解锁
				return;
			}
		}
	}		
}

int processInput(char recvbuf[],int connectfd, char cli_name[])
{
	int i;
	char combuf[COMMANDSIZE];
	char namechange[MAXDATASIZE];
	char passwd[PASSWD];
	char * tokenPtr;
	char * tokenPtr2;

	strcpy(combuf,recvbuf);
	combuf[strlen(combuf)]='\0';
	tokenPtr=(char *)strtok(combuf," ");
			
	while(tokenPtr != NULL)
	{
		if(!strcmp(tokenPtr,"/quit"))
		{
			//send(connectfd,quitbuf,strlen(quitbuf),0);  //send "byte!"
			one_send(cli_name, cli_name, quitbuf);
			return 2;
		}
		else if(!strcmp(tokenPtr,"/help"))
		{		
			ReadHelpFile(cmdbuf);
			//send(connectfd,cmdbuf,strlen(cmdbuf),0);  //send the detail of command 
			one_send(cli_name, cli_name, cmdbuf);
			return 1;
		}
		else if(!strcmp(tokenPtr,"/passwd"))
		{		
			tokenPtr=(char *)strtok(NULL," ");
			if(tokenPtr != NULL)
			{	
				bzero(passwd,sizeof(passwd));				
				strcat(passwd,tokenPtr);						
				passwd[strlen(passwd)]='\0';
				if(changePasswd(cli_name,tokenPtr,connectfd) !=1) //change success
				{
					send(connectfd,pwdbuf0,strlen(pwdbuf0),0);  //send the error of command 
					return 0;
				}	
				send(connectfd,pwdbuf1,strlen(pwdbuf1),0);  //send the success of command 		
				bzero(passwd,sizeof(passwd));
				return 6;				
			}
			else
			{
				send(connectfd,pwdbuf0,strlen(pwdbuf0),0);  //send the error of command 
				return 0;
			}			
			return 6;
		}		
		else if(!strcmp(tokenPtr,"/m"))
		{	
			tokenPtr=(char *)strtok(NULL," ");    //获取信息的发送对象

⌨️ 快捷键说明

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