今天看啥
    热点:

      天发国际娱乐官网:在这方面,云南旅游很有代表性。

      实现在同一台服务器上登录的ssh用户的群聊(聊天室)功能


      直接上代码了,注释还算清晰,有问题欢迎提问指证。

      为方便下载编译,代码都放到一个文件里了。

      服务器是CentOS,客户端用的secureCRT。

       

      /*
      功能:	在同一台服务器上ssh登录的用户可以群聊(聊天室)
      
      原理:		1、通过roomNo.来区分不同的房间或群组;
      		2、以roomNo.作为key来创建一块共享内存,来保存进入到该room的用户列表;
      		3、用户以ssh(或其它方式)登录到服务器,在/dev/pts/目录下都会有一个对应文件;
      		4、自己的用户名和对应的设备文件名可从环境变量(USER和SSH_TTY)中获取到;
      		5、通过向用户对应的设备名中写数据,用户就可以收到,不必开发客户端;
      		6、用户在发送信息时向用户列表中的用户逐个发送,即可实现群聊功能;
      
      		实际上是对“write”命令的加强而已。
      
      遇到的问题:
      		1、显示不显示汉字受终端软件影响,自己配置下;
      		2、获取自己用户名和对应的设备文件名,寻找了很多方式,最终发现通过环境变量最简单;
      		3、没有权限open方式其他用户对应的设备,通过修改/dev/pts/下的文件权限为622解决,
      		最好自己根目录的.bashrc脚本文件中加入“chmod 622 $SSH_TTY”,这样每次登录时会自动修
      		改;暂没找到其它更好方法;
      		4、fgets方式获取的字符串不能backspace,网上朋友说修改VERASE值为0x08,试验发现可以,
      		但删汉字时,一个汉字要对应2个backspace;
      		5、在自己输入信息到一半,但还没有回车发送便收到其它用户的信息时,自己输入的信息
      		被打断,再解决这个问题就更接近完美了;
      
      */
      
      #include   
      #include   
      #include   
      #include  
      #include 
      #include 
      #include 
      #include 
      #include  
      #include 
      #include 
      #include 
      #include 
      
      #ifndef _SHMDATA_H_HEADER  
      #define _SHMDATA_H_HEADER  
      
      //同时在线的用户最大数量,可更改
      #define USER_NUM 20
      #define USER_LEN 30
        
      struct shared_users_st  
      {  
          int written;			//作为一个标志,非0:表示不可写,0表示可读写  
          char users[USER_NUM][USER_LEN];	//记录写入和读取的文本, zhi.wang@/dev/pts/2
      };  
        
      #endif  
      
      void utmpinfo();
      void pwentinfo();
      char *getuser();
      char *gettty();
      void msgparser(char *buffer);
      
      int shmcreate(key_t key);
      int shmdetach(void *shm);
      int shmdestroy(int shmid);
      int shmuseradd(struct shared_users_st *);
      int shmuserclear(struct shared_users_st *);
      int shmuserexit(struct shared_users_st *);
      int shmuserlist(struct shared_users_st *);
      int shmusermsg(struct shared_users_st *, char *);
      bool userinutmp(char *);
      
      void *shm = NULL;
      int shmid;
      int mylocal = -1;	//记录自己在shm中的位置,退出时方便删除
      
      struct termios new; /* 控制终端状态的数据结构,可 man termios 查看*/
      struct termios old;
      
      
      //全局开关
      //匿名发送消息
      bool ishidden = false;
      bool running = true;
      
      char prompt = '_';
      
      static char *help = "\
          :l		List users;\n\
          :c		Clear all users;\n\
          :q		Quit;\n\
          :help	Help;\n\
          :hide	set anonymous;\n\
          :nohide	set noanonymous;\n\
      	";
      
      void sig_handler( int sig);
      void chatroominit();
      void chatroomexit();
      
      void chatroominit()
      {
      	signal(SIGINT, sig_handler);
      
          tcgetattr(0,&old); /* 得到当前的终端状态 */
          new = old; 
      	//printf("old[VERASE]=0x%x\n\n", old.c_cc[VERASE]);
      	new.c_cc[VERASE] = 0x08;	//实现backspace功能
      	tcsetattr(0,TCSANOW,&new); /* 应用新的设置*/
      }
      
      void chatroomexit()
      {
      	tcsetattr(0,TCSANOW,&old);
      	//shmuserclear(shm);
      	shmuserexit((struct shared_users_st *)shm);
      	//shmdetach(shm);
      }
      
      //处理ctrl+c
      void sig_handler( int sig)
      {
      	//printf("%s %d \n", __FUNCTION__, sig);
      	if(sig == SIGINT )
      	{
      		chatroomexit();
      		exit(0);
      	}
      }
      
      int main()  
      {	
      	char buffer[BUFSIZ + 1];//用于保存输入的文本
      	char *roomno;
      	
      	//printf(" ** room NO.: %d\n", sizeof(struct shared_users_st));
      	roomno = getpass("Please enter room No.:");
      	//printf("  ** room NO. is : %s\n", roomno);
      	
      	chatroominit();
      	//setuid(0);
      
      	shmid = shmcreate((key_t)atoi(roomno));
      	shmuseradd((struct shared_users_st *)shm);
      	shmuserlist((struct shared_users_st *)shm);
      	
      	while (running)
      	{
      		printf("%c", prompt);
      		memset(buffer, 0, BUFSIZ + 1);
      		fgets(buffer, BUFSIZ, stdin);
      
      		msgparser(buffer);
      		
      	}
      
      	chatroomexit();
      	exit(EXIT_SUCCESS);  
      }  
      
      //分析输入内容
      void msgparser(char *buffer)
      {
      	char c;
      		
      	switch (c = buffer[0])
      	{
      	case ':':
      		if (strncmp(buffer+1, "q", 1) == 0)
      		{
      			running = false;
      			//检查是否还有在线用户,如没有则销毁
      		}
      		else if (strncmp(buffer+1, "help", 4) == 0)
      		{
      			printf("%s\n", help);
      		}
      		else if (strncmp(buffer+1, "clear", 5) == 0)
      		{
      			shmuserclear((struct shared_users_st *)shm);
      		}
      		else if (strncmp(buffer+1, "l", 1) == 0)
      		{
      			shmuserlist((struct shared_users_st *)shm);
      		}
      		else if (strncmp(buffer+1, "hide", 4) == 0)
      		{
      			ishidden = true;
      		}
      		else if (strncmp(buffer+1, "nohide", 6) == 0)
      		{
      			ishidden = false;
      		}
      		break;
      	case '?':
      		printf("%s\n", help);
      		break;
      	default:
      		//printf("%d %d\n", strlen(buffer), buffer[0]);
      		//空格和换行不发送
      		if ((strlen(buffer) <= 2 && buffer[0] == 32) || 
      			(strlen(buffer) <= 1 && buffer[0] == 10))
      		{
      			break;
      		}
      		//printf("%s\n", buffer);
      		shmusermsg((struct shared_users_st *)shm, buffer);
      	}
      }
      
      char *getuser()
      {
      	return getenv("USER");
      }
      
      char *gettty()
      {
      	return getenv("SSH_TTY");
      }
      
      static void waitwrite(struct shared_users_st *shared)
      {
      	//数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本 
      	//shared->written = 0;
      	while(shared->written == 1)  
      	{  
      		sleep(1);  
      		printf("Waiting...\n");  
      	} 
      }
      
      int shmcreate(key_t key)
      {
          char buffer[BUFSIZ + 1];//用于保存输入的文本  
           
          //创建共享内存  
          shmid = shmget((key_t)key, sizeof(struct shared_users_st), 0666|IPC_CREAT);  
          if(shmid == -1)  
          {  
              fprintf(stderr, "shmget failed\n");  
              //exit(EXIT_FAILURE);  
          }  
          //将共享内存连接到当前进程的地址空间  
          shm = shmat(shmid, (void*)0, 0);  
          if(shm == (void*)-1)  
          {  
              fprintf(stderr, "shmat failed\n");  
              //exit(EXIT_FAILURE);  
          }  
          //printf("Memory attached at %X\n", (int)shm); 
      	
      	return shmid;
      
      }
      
      int shmdetach(void *shm) 
      {
          //把共享内存从当前进程中分离  
          if(shmdt(shm) == -1)  
          {  
              fprintf(stderr, "shmdt failed\n");  
              exit(EXIT_FAILURE);  
          }  
      
      	return 0;
      }
      
      int shmdestroy(int shmid) 
      {
          //printf(" ** %s\n", __FUNCTION__); 
      
      	//删除共享内存  SHM_DEST
          if(shmctl(shmid, IPC_RMID, 0) == -1)  
          {  
              fprintf(stderr, "shmctl(IPC_RMID) failed(%d).\n", shmid);  
              exit(EXIT_FAILURE);  
          }  
      
      	return 0;
      }
      
      int shmuseradd(struct shared_users_st *shared)  
      {  
      	//struct shared_users_st *shared = NULL;
      	char buffer[BUFSIZ + 1];//用于保存输入的文本
      	int i = 0;
      	char *p = NULL;
      
      
          //设置共享内存  
          //shared = (struct shared_users_st*)shm;
      
      	//向共享内存中写入数据  
      	strcat(buffer, getuser());
      	strcat(buffer, "@");
      	strcat(buffer, gettty());
      	//printf("buffer:%s\n", buffer);
      	
      	waitwrite(shared);
      	//向共享内存中写入数据前先置1,其它进程不可写
      	shared->written = 1;
      
      	do
      	{	
      		//没有找到@时,或者找到自己对应的tty时则替换
      		if ((p = strchr(shared->users[i],'@')) == 0)
      		{
      
      			if (mylocal == -1)
      			{
      				//printf("%s %s %d\n", __FUNCTION__, buffer, i);
      				strncpy(shared->users[i], buffer, USER_LEN); 
      				//记录下自己所在位置,退出时自己删除
      				mylocal = i;
      			}
      			else
      			{
      				//printf("%s %s %d reset.\n", __FUNCTION__, shared->users[i], i);
      				memset(shared->users[i], 0, USER_LEN);		
      			}
      		} 
      		else 
      		{
      			//printf("\n\nbuffer: %s != %s %d=%d\n\n", p+1, gettty(), strlen(p+1) ,strlen(gettty()));
      			if (!strncasecmp(p+1, gettty(), strlen(p+1) > strlen(gettty()) ? strlen(p+1) : strlen(gettty()) ))
      			{
      				if (mylocal == -1)
      				{
      					//printf("%s %s %d\n", __FUNCTION__, buffer, i);
      					strncpy(shared->users[i], buffer, USER_LEN); 
      					//记录下自己所在位置,退出时自己删除
      					mylocal = i;
      				}
      				else
      				{
      					//printf("%s %s %d reset.\n", __FUNCTION__, shared->users[i], i);
      					memset(shared->users[i], 0, USER_LEN);		
      				}
      			}
      			//continue;
      
      			//检查user和tty跟当前系统登录的是否匹配(参考w命令)
      			if (userinutmp(shared->users[i]) == false)
      			{
      				printf("  ## %s %s %d autodelete.\n", __FUNCTION__, shared->users[i], i);
      				memset(shared->users[i], 0, USER_LEN);
      			}
      		}
      		//memset(shared->users[i], 0, USER_LEN);
      	} while (++i < USER_NUM);
      
      	//写完数据,设置written使共享内存段可读  
      	shared->written = 0;  
      
      	if (mylocal != -1)
      	{
      		//告诉在线用户,我已加入
      		memset(buffer, 0, BUFSIZ + 1);
      		sprintf(buffer, "\n  ## Welcome %s to our room.\n", shared->users[mylocal]);
      		shmusermsg(shared, buffer);
      	}
      
      	return 0;
      }  
      
      //清空所有用户
      int shmuserclear(struct shared_users_st *shared)  
      {  
      	//struct shared_users_st *shared = NULL;
      	int i = 0;
      	char buffer[BUFSIZ + 1];//用于保存输入的文本
      
          //设置共享内存  
          //shared = (struct shared_users_st*)shm;
      	
      	//数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本  
      	waitwrite(shared);	
      	//向共享内存中写入数据前先置1,其它进程不可写
      	shared->written = 1;
      
      	do
      	{	
      		//找到@时
      		if (rindex(shared->users[i],'@') != 0)
      		{
      			memset(buffer, 0, BUFSIZ + 1);
      			sprintf(buffer, "\n  ## %s has been kicked out of the room.\n\n\n", 
      				shared->users[i]);
      			shmusermsg(shared, buffer);
      
      			memset(shared->users[i], 0, USER_LEN);			
      			//break;
      		} 
      	} while (++i < USER_NUM);
      	
      	//写完数据,设置written使共享内存段可读  
      	shared->written = 0;  
      
      	return 0;
      } 
      
      //退出时只删除自己即mylocal所标记位置
      //如果退出时没有在线用户,则销毁shm
      int shmuserexit(struct shared_users_st *shared)  
      {  
      	//struct shared_users_st *shared = NULL;  
      	char buffer[BUFSIZ + 1];//用于保存输入的文本
      	int i = 0;
      
          //设置共享内存  
          //shared = (struct shared_users_st*)shm;
      
      	//printf("%s %s %d\n", __FUNCTION__, shared->users[mylocal], mylocal);
      	//告诉在线用户,我已离开
      	memset(buffer, 0, BUFSIZ + 1);
      	sprintf(buffer, "\n  ## %s exit the room.\n", shared->users[mylocal]);
      	shmusermsg(shared, buffer);
      	
      	//数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本  
      	waitwrite(shared);  
      	
      	//向共享内存中写入数据前先置1,其它进程不可写
      	shared->written = 1;
      
      	memset(shared->users[mylocal], 0, USER_LEN);
      
      	do
      	{	
      		//找到@时
      		if (rindex(shared->users[i],'@') != 0)
      		{
      			//memset(shared->users[i], 0, USER_LEN);			
      			break;
      		} 
      	} while (++i < USER_NUM);
      
      	//写完数据,设置written使共享内存段可读  
      	shared->written = 0;  
      
      	shmdetach((void *)shared);
      
      	//如果已没有用户在线,则销毁
      	if (i == USER_NUM)
      	{
      		//此处暂未解决“不能其他用户创建的共享内存”的问题,所有注释掉
      		//shmdestroy(shmid);
      	}
      	
      	return 0;
      }  
      
      int shmuserlist(struct shared_users_st *shared)
      {  
      	//struct shared_users_st *shared = NULL; 
      	int i = 0;
      
          //设置共享内存  
          //shared = (struct shared_users_st*)shm;
      	
      	//数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本  
      	//waitwrite(shared); 
      	
      	//向共享内存中写入数据前先置1,其它进程不可写
      	//shared->written = 1;
      
      	printf("  zz%s\n", "zzzzzzzzzzzzzzzzzzzzzzzzzzzz");
      
      	do
      	{	
      		//找到@时
      		if (rindex(shared->users[i],'@') != 0)
      		{
      			printf("  zz %d %s\n", i, shared->users[i]);
      			
      			//break;
      		} 
      	} while (++i < USER_NUM);
      
      	printf("  zz%s\n", "zzzzzzzzzzzzzzzzzzzzzzzzzzzz");
      	
      	//写完数据,设置written使共享内存段可读  
      	//shared->written = 0;  
      
      	return 0;
      }  
      
      int shmusermsg(struct shared_users_st *shared, char *buffer)
      {  
      	//struct shared_users_st *shared = NULL; 
      	int i = 0;
      	char buff[BUFSIZ + 1];//用于保存输入的文本
      
          //设置共享内存  
          //shared = (struct shared_users_st*)shm;
      	
      	//数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本  
      	//waitwrite(shared);  
      	
      	//向共享内存中写入数据前先置1,其它进程不可写
      	//shared->written = 1;
      
      	if (!ishidden)
      	{	
      		sprintf( buff, "  ** %s: %s", getuser(), buffer);
      		strcpy(buffer, buff);
      	}
      
      
      	do
      	{	
      		//找到@时
      		if (rindex(shared->users[i],'@') != 0 ) //&& i != mylocal
      		{
      			char *p;
      			int fd;
      
      			//发送给其它用户时,换行\n后输出
      			if (i != mylocal)
      			{
      				sprintf( buff, "%s", buffer);
      			}
      			else
      			{
      				//\033[1A 先回到上一行 //\033[K 清除该行
      				sprintf( buff, "\033[1A\033[K%s", buffer);
      			}
      			//strcpy(buffer, buff);
      
      			//printf("%s %s %d\n", __FUNCTION__, strchr(shared->users[i],'@')+1, i);
      
      			if ((p = strchr(shared->users[i],'@')) == 0)
      			{
      				//perror("open error");
      				continue;
      			}
      
      			//发送消息之前先判断该用户是否在线
      			if ((fd = open(p+1, O_WRONLY)) < 0)
      			{
      				perror("open error");
      				printf("%s\n", shared->users[i]);
      				//exit(EXIT_FAILURE);
      			}
      
      			if (write(fd, buff, strlen(buff)+1) != strlen(buff)+1)
      			{
      				perror("write error");
      				//exit(EXIT_FAILURE);
      			}
      
      			close(fd);
      			
      			//break;
      		} 
      	} while (++i < USER_NUM);
      	
      	//写完数据,设置written使共享内存段可读  
      	//shared->written = 0;  
      
      	return 0;
      }  
      
      //在utmp文件(当前在线用户,即w命令展示结果)中找到返回非0,未找到返回0
      bool userinutmp(char *userinfo)
      {
      	struct utmp *u;
      	char *p, *tty, user[USER_LEN];
      
      	memset(user, 0, USER_LEN);
      	strncpy(user, userinfo, strlen(userinfo));
      
      	p = strtok(user, "@");
      	//user = p;
      	p = strtok(NULL, "@");
      	tty = p;
      	//printf("%s %s %s.\n", user, tty, userinfo);
      
      	struct utmp ut;
      	strcpy (ut.ut_line,tty+5);
      	while ((u=getutline(&ut)))
      	{
      		//printf("-%d %s %s %s \n",u->ut_type,u->ut_user,u->ut_line,u->ut_host);
      		//如果找到匹配
      		if (!strcmp(u->ut_user, user))
      		{
      			endutent();
      			return true;
      		}
      	}
      
      	endutent();
      
      	return false;
      
      }
      
      #if 1
      
      void pwentinfo()
      {
      	struct passwd *user;
      
      	if((user = getpwuid(geteuid()))!=0)
      	{
      		printf("%s:%d:%d:%s:%s:%s\n",user->pw_name,user->pw_uid,user->pw_gid,
      		user->pw_gecos,user->pw_dir,user->pw_shell);
      	}
      
      	endpwent();
      	
      	printf("uid is %d\n",getpgid(getegid()));
      	printf("egid is %d\n",getegid());
      	printf("gid is %d\n",getpgrp());
      
      }
      #endif

      www.1click-soft.comtruehttp://www.1click-soft.com/wlxy/1122204.htmlTechArticle实现在同一台服务器上登录的ssh用户的群聊(聊天室)功能 直接上代码了,注释还算清晰,有问题欢迎提问指证。 为方便下载编译,代码...

      相关文章

      相关搜索: 聊天室 ssh 服务器

      帮客评论

      视觉看点
      百度 360 搜狗