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

📄 chat1.0pre5.pl

📁 基于socket的聊天室实现原理 付论文
💻 PL
📖 第 1 页 / 共 2 页
字号:
   my $id;
   if ($nick ne "" && $nick ne "所有人"){
	   foreach $id (keys %CLIENTS) {
	      if ($CLIENTS{$id}->[1] eq $nick) {
	         return $id;
	      }
	   }
   }
   return undef;
}

sub sendmsg{
#___
#  |----动作-----系统管理命令
#  |          |
#  |          |--普通动作
#  |
#  |
#  |----说话-----对所有人
#             |
#             |--对某个人----公开说话
#                         |
#                         |--私聊

#sendmsg($sid,$FORM{'talkto'},$FORM{'message'},$FORM{'ws'});
	my ($sid,$talkto,$msg,$ws)=@_;
	#检查参数
	if ($talkto eq "所有人"){
		$ws="";
	}

	#先对msg进行必要的处理,禁止html,前后空格已经去掉了
	if ($msg eq ""){
		return;
	}
	$msg=~s/\</&lt\;/g;
	$msg=~s/\>/&gt\;/g;

	if (!id_ok($sid)){
		return;
	}
	my $name=$CLIENTS{$sid}->[1];

	if ($msg=~m,^/,){#动作
		$msg=$';
		my ($cmd,$para,$junk)=split(/\s+/,$msg,3);
		if (length($para)>0){#动作可以带参数,如果带参数,那么将覆盖talkto的内容
			$talkto=$para;
		}
		my $did=get_sid($talkto);#如果$talkto存在,则返回sid
		my $did_ok;
		if (id_ok($did)){
			$did_ok=1;
		}else{
			$did_ok=0;
		}
		if ($cmd=~m,^/,){#系统管理命令
			$cmd=$';
			my $info="";
			my $sock=$CLIENTS{$sid}->[0];
			if (!($MOD{$name}||$ADMIN{$name})){#检查权限
				$info="你的权限不够";
			}elsif ($talkto eq "所有人"){#管理命令只能对某个人使用
				$info="请先选择命令对象";
			}else{
				if ($cmd eq "ip"){
					if ($did_ok){
						my $dsock=$CLIENTS{$did}->[0];
						my $ip_addr;
						if (!eval{$ip_addr=$dsock->peerhost;}){
							log_event("Get peer ip error!$@");
							$ip_addr="N/A";
						}
						$info="$talkto的IP地址是$ip_addr";
					}else{
						$info="$talkto已经离开";
					}
				}elsif($cmd eq "filter"){
					if ($did_ok){
						$sys_filter{$talkto}=1;
						my @ls=keys %sys_filter;
						my $list="@ls";
						if ($list ne ""){
							$list="($list)";
						}
						
						$info="$talkto被加入系统过滤表$list";
					}else{
						$info="$talkto已经离开";
					}					
				}elsif($cmd eq "unfilter"){
					if (exists($sys_filter{$talkto})){
						delete $sys_filter{$talkto};
						$info="$talkto已从系统过滤名单中移出。";
					}else{
						$info="$talkto不在过滤名单里。";
					}
				}elsif($cmd eq "kick"){
					if ($did_ok){#也许需要缺席审判
						if ($name eq $talkto){
							$info="干吗踢自己?";
						}elsif($ADMIN{$talkto}){
							$info="嘿嘿,你踢不了他:-)";
						}else{
							#需要广播这个消息,同时保存在blacklist里
							$blacklist{$talkto}=1;
							notice("$talkto被赶出聊天室");
				            log_event("$name kicked $talkto out");
							
							exitclient($did);
						}
					}else{
						$info="$talkto已经离开";
					}
				}elsif($cmd eq "unkick"){#释放以前踢过的人
					delete $blacklist{$talkto};
					$info="$talkto被放出来了:-)";
		            log_event("$name unkick $talkto");
					
				}elsif($cmd eq "grant"){#授权,保存在内存里,重启以后失效
					if (!$ADMIN{$name}){#检查权限,只有管理员(level=0)可以授权
						$info="你的权限不够";
					}else{
						#if ($did_ok){
							$MOD{$talkto}=1;
							$info="$talkto成为室主";
						#}else{
						#	$info="$talkto已经离开";
						#}
					}
				}elsif($cmd eq "revoke"){
					if (!$ADMIN{$name}){#检查权限,只有管理员(level=0)可以取消授权
						$info="你的权限不够";
					}else{
						if ($MOD{$talkto}){
							delete $MOD{$talkto};
							$info="$talkto被取消室主权限";
						}else{
							$info="$talkto不是室主";
						}
					}
				}else{#
					$info="系统不支持这个命令";
				}
			}
			if ($info ne ""){
				$info="<font color=black>【系统消息】$info</font><br>";
				$out_buf{$sock}.=$info;
			}
		}else{#普通动作〖〗
			my $info="";
			if ($cmd eq "filter"){
				if ($talkto eq "所有人"){
					$info="【系统消息】请选择过滤对象<br>";
				}else{
					if ($did_ok){
						$CLIENTS{$sid}->[4]->{$talkto}=1;
						my $f_ref=$CLIENTS{$sid}->[4];
						my @ls=keys %{$f_ref};
						my $list="@ls";
						if ($list ne ""){
							$list="($list)";
						}
						$info="【系统消息】$talkto已被加入$name的过滤名单$list,取消过滤请用命令/unfilter<br>";
					}else{
						$info="【系统消息】过滤对象不存在<br>";
					}
				}
				my $sock=$CLIENTS{$sid}->[0];
				$out_buf{$sock}.=$info;
			}elsif($cmd eq "unfilter"){
				if (exists($CLIENTS{$sid}->[4]->{$talkto})){
					delete $CLIENTS{$sid}->[4]->{$talkto};
					$info="【系统消息】$talkto已从$name的过滤名单中移出。<br>";
				}else{
					$info="【系统消息】$talkto不在过滤名单里。<br>";
				}
				my $sock=$CLIENTS{$sid}->[0];
				$out_buf{$sock}.=$info;
			}else{#其他动作,在@emote里,需要广播
				if ($talkto ne "所有人"){#对某个人做动作
					if (!$did_ok){#如果不在聊天室里
						$info="【系统消息】$talkto已经离开<br>";
						my $sock=$CLIENTS{$sid}->[0];
						$out_buf{$sock}.=$info;
						return;
					}
				}
				$info=emote($name,$talkto,$cmd);
				my $color=$CLIENTS{$sid}->[6];
				if (!$info){
					$info = qq(【系统消息】<a href="javascript:parent.d.csn('$name');" target=d>$name</a>自言自语不知在说什么。<br>);
					my $sock=$CLIENTS{$sid}->[0];
					$out_buf{$sock}.=$info;
					return;
				}
				my $key;
				foreach $key (keys %CLIENTS){
					if (!id_ok($key)){
						next;
					}
					if (($sys_filter{$name} && $key ne $sid)||$CLIENTS{$key}->[4]->{$name}){
						next;
					}

					my $output=$info;
					if ($key eq $sid || (defined($did) && $key eq $did)){#可以改写此处以区分相关内容
						$output="【动作】$output";
					}else{
						$output="【动作】$output";
					}
					$output="<font color=$color>$output</font><br>";
					my $sock=$CLIENTS{$key}->[0];
					$out_buf{$sock}.=$output;
				}

			}
		}
	}else{#对话
		if($talkto eq "所有人"){#对所有人说
			my ($key,$output);
			my $color=$CLIENTS{$sid}->[6];
			foreach $key (keys %CLIENTS){
				if (!id_ok($key)){
					next;
				}
				if (($sys_filter{$name} && $key ne $sid)||$CLIENTS{$key}->[4]->{$name}){
					next;
				}
				my $head;
				if ($key eq $sid){
					$head="【闲聊】";
				}else{
					$head="【闲聊】";
				}
				my $sock=$CLIENTS{$key}->[0];
				$output=qq(<font color=$color>$head<a href="javascript:parent.d.csn('$name');" target=d>$name</a>:$msg</font><br>);
				$out_buf{$sock}.=$output;
			}
		}else{#对某个人说
			my $did=get_sid($talkto);#如果$talkto存在,则返回sid
			if (id_ok($did)){
				my $color=$CLIENTS{$sid}->[6];
				if ($ws eq "on"){#私聊
					my $output=qq(<font color=$color> [私人对话] <a href="javascript:parent.d.csn('$name');" target=d>$name</a>对<a href="javascript:parent.d.csn('$talkto');" target=d>$talkto</a>:$msg</font><br>);
					if ($name ne $talkto){
						if (!$sys_filter{$name} && !$CLIENTS{$did}->[4]->{$name}){
							my $dsock=$CLIENTS{$did}->[0];
							$out_buf{$dsock}.=$output;
						}
					}

					my $sock=$CLIENTS{$sid}->[0];
					$out_buf{$sock}.=$output;
				}else{#公开对某人说
					my $key;
					foreach $key (keys %CLIENTS){
						if (!id_ok($key)){
							next;
						}
						if (($sys_filter{$name} && $key ne $sid)||$CLIENTS{$key}->[4]->{$name}){
							next;
						}

						my ($head);
						if ($key eq $sid || $key eq $did){
							$head="【闲聊】";
						}else{
							$head="【闲聊】";
						}
						my $sock=$CLIENTS{$key}->[0];
						my $output=qq(<font color=$color>$head<a href="javascript:parent.d.csn('$name');" target=d>$name</a>对<a href="javascript:parent.d.csn('$talkto');" target=d>$talkto</a>:$msg</font><br>);
						$out_buf{$sock}.=$output;
					}
				}
			}else{#用户已经离开
				my $sock=$CLIENTS{$sid}->[0];
				my $output=qq(<font color=black>【请注意】$talkto已经离开了</font><br>);
				$out_buf{$sock}.=$output;
			}
		}
	}
}

sub broadcast{
	my $msg=shift;
	my ($key);
	foreach $key (keys %CLIENTS){
		if (id_ok($key)){
			$out_buf{$CLIENTS{$key}->[0]}.=$msg;
		}
	}
}

sub id_ok{
	my $sid=shift;
	if (defined($sid) && defined($CLIENTS{$sid})){
		my $sock=$CLIENTS{$sid}->[0];
		if (defined($sock) && $sock->opened && $sock->peername){
			return 1;
		}
	}
	return 0;
}

sub check_clients{
	my ($key);
	foreach $key (keys %CLIENTS){
		if (!defined($CLIENTS{$key})){
			delete $CLIENTS{$key};
			next;
		}
		my $sock=$CLIENTS{$key}->[0];
		my $name=$CLIENTS{$key}->[1];
		if (!defined($sock)){
			#print "Socket not defined\n";

			if (time()-$config{'timeout'}>$CLIENTS{$key}->[5]){
				notice("$CLIENTS{$key}->[1]断线离开") if ($name);
	            log_event("$name offline");
				
				delete $CLIENTS{$key};
			}
			next;
		}
		if (!$sock->opened||!$sock->peername){
			$sel->remove($sock);
			$CLIENTS{$key}->[0]=undef;
			$CLIENTS{$key}->[5]=time();#断线不马上通知,主要为刷新处理
			next;
		}
	}
}

sub antiidle {#定时发送信息防止session time out,由在线名单调用
   my ($msid) = $_[0];
   if (!id_ok($msid)){
   	return;
   }
   my($sock) = $CLIENTS{$msid}->[0];
   $out_buf{$sock}.="\n<!--antiidle-->\n";

}

sub rand_str{
	my $num=shift;
	my $i;
	my $str="";
	my @rand_chars=('a'..'z','A'..'Z','0'..'9');
	for ($i=0;$i<$num;$i++){
		$str.=$rand_chars[rand(@rand_chars)];
	}
	return $str;
}

sub check_pass{#检查密码,login时调用
#测试版本,不验证密码,只保留一个管理员admin,密码是"win3.11"
#...
#我们实际使用的版本用户数据库是放在MySql里,包括用户权限等数据都在数据库里,
#因此程序的身份验证及权限管理都需要做改动。

	my ($name,$passwd)=@_;
	if (!($name&&$passwd)){
		return (0,2,1);
	}
    if ($name eq "admin" && $passwd eq crypt($config{'admin_pass'},$passwd)){
            return (1,0,1);
    }elsif($name eq "admin"){
            return (0,2,1);
    }else{
            return (1,2,0);
    }
}

sub check_auth{#检查身份,发言时调用,参数是sid,加密过的密码
	my ($sid,$passwd)=@_;
	if (!($sid&&$passwd)){
		return 0;	
	}
	if ($CLIENTS{$sid}->[2] eq $passwd) {
		return 1;
	}else{
		return 0;
	}
}

sub exitclient {
	my $sid=shift;
	my $sock=$CLIENTS{$sid}->[0];
	if (defined $sock) {
		$sel->remove($sock);
		delete $chat_sock{$sock};
		delete $out_buf{$sock};
		$sock->close;
	}
	delete $CLIENTS{$sid};
}

sub notice{
	my $msg=shift;
	my $output=qq(
		<font color=black>
		【通知】$msg<br>
		</font>
	);
	broadcast($output);
}

sub offline{
	my $sid=shift;
	if (id_ok($sid)){
		my $nick=$CLIENTS{$sid}->[1];
		notice("$nick离开了聊天室");
        log_event("$nick left");
		exitclient($sid);
	}
}

sub trim{
	my $str=shift;
	$str=~s/^\s*//;
	$str=~s/\s*$//;
	return $str;
}

sub emote{
# 动作
# usage: emote(talker,listener,action),
# 其中action可以是中文,listener如果是"",就是对自己说
	my ($talker,$listener,$action) = @_;
	if ($action eq ""){
		return "";
	}
	if ($listener eq "所有人"){
		$listener="";
	}
	my $EMOTE="";
	my $isEnglish;
	if ($action=~/[\xA1-\xFE]/){#判断动作是否中文
		$isEnglish=0;
	}else{
		$isEnglish=1;
	}
	foreach  (@emote) {
		my ($isdisp,$english,$chinese,$one,$two)=split(/~~~/,$_);
		my $cmp;
		if ($isEnglish){
			$cmp=\$english;
		}else{
			$cmp=\$chinese;
		}
		if (${$cmp} eq $action) {
			#find the emote words

			#talk to listener
			my $from=qq(<a href="javascript:parent.d.csn('$talker');" Target=d>$talker</a>);
			if ($listener) {
				my $to=qq(<a href="javascript:parent.d.csn('$listener');" Target=d>$listener</a>);
				$two=~s/self/$from/g;
				$two=~s/target/$to/g;
				$EMOTE=$two;
			}
			#talk to oneself
			else{#如果listener为"",或者是“所有人”,就是自言自语,
				$one=~s/self/$from/g;
				$EMOTE=$one;
			}
			last;
		}
		#Can not find the emote words
		else{
			$EMOTE="";
		}
	}
	return $EMOTE;
}


# nonblock($socket) puts socket into nonblocking mode
sub nonblock {
	return;
    my $socket = shift;
    my $flags;
    
    $flags = fcntl($socket, F_GETFL, 0)
            or die "Can't get flags for socket: $!\n";
    fcntl($socket, F_SETFL, $flags | O_NONBLOCK)
            or die "Can't make socket nonblocking: $!\n";
}

sub log_event{
	my $msg=shift;
	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime();
	$mon++;
	$year+=1900;
    my $logtime="$year-$mon-$mday $hour:$min:$sec";
    $lh->log("$logtime $msg");
}

⌨️ 快捷键说明

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