系统:ubuntu10.10
实验题目: 编写⼀个 write 简单版本,能够接受用户名作为参数,并 在屏幕上显示你想通信
的用户。查看 write 的标准版本显示的内容。 你的程序应该可以处理这样的特殊情况:你想
聊天的人可能没有登录。另⼀方 面,你想聊天的人可能登录了若干个终端。
解决过程:
记得当时安装虚拟系统时,只设定了一个用户,为了做这个实验我必须添加几个用户。如果你系统中已经有多个用户可以省略这一步。
step1、建立多个用户
建立用户的命令为:sudo useradd -d /usr/sam -m sam
建立一个名字叫sam的用户,使用sudo是因为权限不够,必须在root下才能使用useradd,所以在非root下必须添上sudo。注意这时你还不能使用这个用户名登陆,为什么?因为你还没给他授权啊!怎么授权,很简单,给他个密码就得了。
给新建的用户添加密码:sudo passwd sam
然后根据提示输入新密码。
至此用户创建完毕,你可以switch user试试成功没有。
step2、通过用户名找到所在的终端
思路是从utmp文件中根据用户名进行搜索,找到和目的用户名相同的记录,并保存。注意满足条件的记录可能有多条,因为那个用户可能打开了多个终端。所以我们得用一个数组存储。这个数组只要存储tty名字就行了。下面就是这个函数的代码。
char ** get_tty( char *logname ) /* * purpose: find the tty at which 'logname' is logged in * returns: a string or NULL if not logged in * errors: does not handle multiple logins */ { static struct utmp utrec[MAX];/* set static because retval is a local value */ int utfd; int namelen = sizeof( utrec[0].ut_name ); char *retval[MAX] = {NULL} ; int index = 0; if ( (utfd = open( UTMP_FILE, O_RDONLY )) == -1 ) /* open utmp */ return NULL; /* look for a line where the user is logged in */ while( read( utfd, &utrec[index], sizeof(struct utmp)) == sizeof(struct utmp) ) if ( strncmp(logname, utrec[index].ut_name, namelen ) == 0 )/* */ { retval[index++] = utrec[index].ut_line ; } close(utfd); /* close & go */ return retval; }
step3、通过向目标tty文件写入数据来达到聊天的目的
通过步骤2我们已经通过用户名获得了终端文件名。根据这个终端文件名我们就可以进行聊天了。上面提到了一个用户可能会打开多个终端,所以会有多个终端名,注意要有提醒用户做出选择的代码。接下来主要讲讲如何向对方的终端文件写入数据来达到聊天的目的。
假设tty_name是用户的打开的某个终端的文件名,首先打开这个终端文件:
sprintf(buf, "/dev/%s", tty_name);
fd = open( buf, O_WRONLY );
打开后就可以从键盘中读入,并把内容发送给对方:
while( fgets(buf, BUFSIZ, stdin) != NULL ){ /* write to user */
if ( write(fd, buf, strlen(buf)) == -1 )
break;
}
到此,核心部分都已经描述清楚了。剩下的就是添砖加瓦,直到满足题目需求。