chat_server.pl 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #!/usr/bin/perl
  2. #
  3. ## Translation of: https://rosettacode.org/wiki/Chat_server#Python
  4. #
  5. # Create server:
  6. # perl chat_server.pl
  7. # Connect to the chat via telnet:
  8. # telnet localhost 4004
  9. use 5.010;
  10. use strict;
  11. use warnings;
  12. use threads;
  13. use threads::shared;
  14. use IO::Socket::INET;
  15. use Time::HiRes qw(sleep ualarm);
  16. my $HOST = "localhost";
  17. my $PORT = 4004;
  18. my @open;
  19. my %users : shared;
  20. sub broadcast {
  21. my ($id, $message) = @_;
  22. print "$message\n";
  23. foreach my $i (keys %users) {
  24. if ($i != $id) {
  25. $open[$i]->send("$message\n");
  26. }
  27. }
  28. }
  29. sub sign_in {
  30. my ($conn) = @_;
  31. state $id = 0;
  32. threads->new(
  33. sub {
  34. while (1) {
  35. $conn->send("Please enter your name: ");
  36. $conn->recv(my $name, 1024, 0);
  37. if (defined $name) {
  38. $name = unpack('A*', $name);
  39. if (exists $users{$name}) {
  40. $conn->send("Name entered is already in use.\n");
  41. }
  42. elsif ($name ne '') {
  43. $users{$id} = $name;
  44. broadcast($id, "+++ $name arrived +++");
  45. last;
  46. }
  47. }
  48. }
  49. }
  50. );
  51. ++$id;
  52. push @open, $conn;
  53. }
  54. my $server = IO::Socket::INET->new(
  55. Timeout => 0,
  56. LocalPort => $PORT,
  57. Proto => "tcp",
  58. LocalAddr => $HOST,
  59. Blocking => 0,
  60. Listen => 1,
  61. Reuse => 1,
  62. );
  63. local $| = 1;
  64. print "Listening on $HOST:$PORT\n";
  65. while (1) {
  66. my ($conn) = $server->accept;
  67. if (defined($conn)) {
  68. sign_in($conn);
  69. }
  70. foreach my $i (keys %users) {
  71. my $conn = $open[$i];
  72. my $message;
  73. eval {
  74. local $SIG{ALRM} = sub { die "alarm\n" };
  75. ualarm(500);
  76. $conn->recv($message, 1024, 0);
  77. ualarm(0);
  78. };
  79. if ($@ eq "alarm\n") {
  80. next;
  81. }
  82. if (defined($message)) {
  83. if ($message ne '') {
  84. $message = unpack('A*', $message);
  85. broadcast($i, "$users{$i}> $message");
  86. }
  87. else {
  88. broadcast($i, "--- $users{$i} leaves ---");
  89. delete $users{$i};
  90. undef $open[$i];
  91. }
  92. }
  93. }
  94. sleep(0.1);
  95. }