Directly on the code, the comments are clear, there are questions to welcome questions to testify.
To facilitate the compilation of the download, the code is placed in a file.
The server is CentOS, the client uses the SECURECRT.
/* Function: SSH login on the same server user can group chat (chat room) principle: <span style= "White-space:pre" ></span>1, through Roomno. To distinguish between different rooms or groups; 2. Take Roomno. As key to create a piece of shared memory, to save the list of users into the space, 3, the user to SSH (or other means) log on to the server, in the/dev/pts/directory will have a corresponding file; 4, The user name and the corresponding device file name can be obtained from the environment variables (user and Ssh_tty), 5, by the user corresponding to the device name to write data, users can receive, do not have to develop the client, 6, the user send the message to the user list of users, one by one, you can achieve group chat function is actually an enhancement to the "write" command. Problems encountered: 1, display does not display Chinese characters affected by the terminal software, its own configuration under; 2, to obtain their own user name and corresponding device file name, looking for a lot of ways, and finally found through the environment variables the simplest; 3, no permissions open way other users corresponding devices, by modifying/dev/pts/ Under the file permissions for 622 resolution, it is best to add "chmod 622 $SSH _tty" in the. bashrc script file of your root directory so that it will be modified automatically each time you log in, and no other better method is found; 4, fgets method gets the string cannot backspace, Online friends said modified Verase value for 0x08, the experiment found can, but the deletion of Chinese characters, a Chinese character to correspond to 2 backspace;5, in their own input information to half, but has not been sent to the other users to send the information, their input information is interrupted, and then solve the problem is closer to perfect ; */#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include < fcntl.h> #include <utmp.h> #include <pwd.h> #include <sys/types.h> #include <sys/shm.h> # Include <signal.h> #include <stdbool.h> #include <termios.h> #include <curses.h> #ifndef _ Shmdata_h_heaDER #define _SHMDATA_H_HEADER//maximum number of simultaneous users, can change the # define User_num 20#define User_len-struct Shared_users_st {in T written;//as a flag, not 0: represents non-writable, 0 represents the text that can be read and written to a char users[user_num][user_len];//record, [email protected]/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;//record itself in sh Position in M, easy to remove struct termios new when exiting; /* Control the data structure of the terminal state, can man Termios view */struct termios old;//Global switch//anonymous send message bool Ishidden = False;bool running = True;char prompt = ' _ '; static char *help = ": Llist users;\n:cclear all Users;\n:qquit;\n:helphelp;\n:hideset anonymous;\n : NoHideset noanonymous;\n "; void Sig_handler (int sig); void Chatroominit (); void Chatroomexit (); void Chatroominit () {signal (SIGINT, Sig_handler); Tcgetattr (0,&old); /* Get the current terminal status */new = old; printf ("old[verase]=0x%x\n\n", Old.c_cc[verase]); New.c_cc[verase] = 0x08;//implements BACKSPACE function tcsetattr (0,tcsanow, &new); /* Apply the new settings */}void Chatroomexit () {tcsetattr (0,tcsanow,&old);//shmuserclear (SHM); Shmuserexit ((struct shared_ Users_st *) SHM);//shmdetach (SHM);} Handles ctrl+cvoid Sig_handler (int sig) {//printf ("%s%d \ n", __function__, Sig), if (sig = = SIGINT) {chatroomexit (); exit (0);}} int main () {char Buffer[bufsiz + 1];//is used to save the input text char *roomno;//printf ("* * * *.:%d\n", sizeof (struct shared_users_st) ); Roomno = Getpass ("Please enter the box No.:");//printf ("* * *. 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); }//Parse input void Msgparser (char *buffer) {char c;switch (c = buffer[0]) {case ': ': if (strncmp (buffer+1, "Q", 1) = = 0) {Running = false;//Check if there are still online users, if not, destroy}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 '? ':p rintf ("%s\n", help), break;default://printf ("%d%d\n", strlen (buffer), buffer[0]);//spaces and line breaks do not send 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) {//data has not been read yet, wait for data to be read, cannot write text to shared memory//shared->written = 0;while ( Shared->written = = 1) {sleep (1); printf ("waiting...\n"); }}int shmcreate (key_t key) {char Buffer[bufsiz + 1];//is used to save the input text//create shared memory Shmid = Shmget ((key_t) key, Siz EOF (struct Shared_users_st), 0666| Ipc_creat); if (Shmid = =-1) {fprintf (stderr, "Shmget failed\n"); Exit (Exit_failure); }//Connect the shared memory to the address space of the current process 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) {//separates shared memory from the current process if (SHMDT (SHM) = =-1) {fprintf (stderr, "Shmdt failed\n"); Exit (Exit_failure); } return 0;} int Shmdestroy (int shmid) {//printf ("* *%s\n", __function__);//delete shared memory 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];//is used to save the output into the text int i = 0;char *p = NULL; Set Shared memory//shared = (struct shared_users_st*) shm;//write data to shared memory strcat (buffer, GetUser ()); strcat (buffer, "@"); Strcat (b Uffer, Gettty ()),//printf ("buffer:%s\n", buffer), waitwrite (Shared),///To write data to shared memory before 1, other processes are not writable Shared->written = 1; do{//if no @ is found, or if the corresponding TTY is found, replace if ((P = STRCHR (shared->users[i], ' @ ') = = 0) {if (mylocal = =-1) {//printf ("%s%s%d\n", __f unction__, buffer, i); strncpy (Shared->users[i], buffer, user_len); Record your location, delete mylocal = i when exiting;} 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, Gett Ty (), strlen (p+1) > strlen (gEttty ())? Strlen (p+1): strlen (Gettty ())) {if (mylocal = =-1) {//printf ("%s%s%d\n", __function__, buffer, i); strncpy (shared->u Sers[i], buffer, user_len); Record your location, delete mylocal = i when exiting;} else{//printf ("%s%s%d reset.\n", __function__, Shared->users[i], i); memset (Shared->users[i], 0, User_len);}} continue;//Check if the user and TTY match the current system login (Reference w command) 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);//write data, set written to make shared memory segment readable Shared->written = 0; if (mylocal! =-1) {//Tell the online user that I have joined memset (buffer, 0, Bufsiz + 1); sprintf (buffer, "\ n # # Welcome%s to our room.\n", shared-& Gt;users[mylocal]); shmusermsg (shared, buffer);} return 0;} Clear all user int shmuserclear (struct Shared_users_st *shared) {//struct Shared_users_st *shared = null;int i = 0;char buffer [Bufsiz + 1];//for saving input text//setting shared memory//shared = (struct shared_users_st*) shm;//data has not been read, wait for the data to be read, cannot write to the shared memory waitwrite (shared);//write data to the shared memory before 1, other processes are not writable shared-> Written = 1;do{//found @ if (Rindex (shared->users[i], ' @ ')! = 0) {memset (buffer, 0, Bufsiz + 1); sprintf (buffer, "\ n # #%s ha s been kicked out of the room.\n\n\n ", Shared->users[i]); shmusermsg (gkfx, buffer); memset (Shared->users[i], 0, User_len);//break;} } while (++i < user_num);//write data, set written to make shared memory segment readable Shared->written = 0; return 0;} When exiting, delete only the location marked by mylocal//If there is no online user at the time of exiting, destroy Shmint shmuserexit (struct Shared_users_st *shared) {//struct Shared_users_ St *shared = NULL; Char Buffer[bufsiz + 1];//is used to hold the input text int i = 0; Set Shared memory//shared = (struct shared_users_st*) shm;//printf ("%s%s%d\n", __function__, shared->users[mylocal], Mylo CAL);//Tell the online user that I have left memset (buffer, 0, Bufsiz + 1); sprintf (buffer, "\ n # #%s exit the room.\n", Shared->users[mylocal]); s Hmusermsg (shared, buffer);//data has not been read, wait for the data to be read, cannot write to the shared memory waitwrite (shared); 1 before writing to the shared memory, other processes are not writable shared->written = 1;memset (shared->users[mylocal], 0, User_len);d o{//Find @ When (Rindex (shared->users[i], ' @ ')! = 0) {// memset (Shared->users[i], 0, User_len); } while (++i < user_num);//write data, set written to make shared memory segment readable Shared->written = 0; Shmdetach (void *) shared);//If no user is online, destroy if (i = = User_num) {//the "No other user created shared memory" issue is not resolved here, all comments Off//shmdestroy (Shmid);} return 0;} int shmuserlist (struct Shared_users_st *shared) {//struct Shared_users_st *shared = NULL; int i = 0; Set Shared memory//shared = (struct shared_users_st*) shm;//data has not been read, wait for data to be read, cannot write to shared memory//waitwrite (shared); Before writing the data to the shared memory 1, the other process is not writable//shared->written = 1;printf ("zz%s\n", "zzzzzzzzzzzzzzzzzzzzzzzzzzzz");d o{//find @ if ( Rindex (Shared->users[i], ' @ ')! = 0) {printf ("zz%d%s\n", I, Shared->users[i]);//break;}} while (++i < user_num);p rintf ("zz%s\n", "zzzzzzzzzzzzzzzzzzzzzzzzzzzz");//write data, set written to make shared memory segments readable//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];//for saving input text//setting shared memory//shared = (struct shared_users_st*) shm;//data has not been read, wait for data to be read, no can write text//waitwrite (shared) to shared memory; Before writing the data to the shared memory 1, the other process is not writable//shared->written = 1;if (!ishidden) {sprintf (Buff, "* *%s:%s", GetUser (), buffer); strcpy (b Uffer, buff);} do{//Find @ When if (Rindex (shared->users[i], ' @ ')! = 0)//&& i! = Mylocal{char *p;int fd;//when sent to another user, after line break \ n Output if (i! = My Local) {sprintf (buff, "%s", buffer);} ELSE{//\033[1A go back to the previous line//\033[k clear the line 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;} Before sending a message, determine if the user is online if (fd = open (p+1, o_wronly) < 0) {perror ("open error");p rintf ("%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);//write data, set written to make shared memory segment readable//shared->written = 0; return 0;} Found in utmp file (current online user, W command display result) returned non 0, not found return 0bool 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 (&u T)) {//printf ("-%d%s%s%s \ n", u->ut_type,u->ut_user,u->ut_line,u->ut_host);//If a match is found (!strcmp (u-> Ut_user, user) {endutent (); return true;}} Endutent (); return false;} #if 1void 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 ();p rintf ("UID is%d\n", Getpgid (Getegid ()));p rintf ("Egid are%d\n", Getegid ());p rintf ("GID is%d\n", GETPGRP ()) ;} #endif
Group Chat (chat room) functionality for SSH users who are logged on on the same server