2015-09-22 16 views
5

Tôi đang cố gắng viết một ứng dụng trò chuyện mạng cơ bản trong Perl cho mục đích học tập. Tôi hiện đang có một chương trình máy chủ và máy khách hoạt động gần như tôi muốn. Nhiều khách hàng có thể kết nối với máy chủ và gửi tin nhắn đến và từ đó. Tuy nhiên, tôi không thực sự chắc chắn làm thế nào để đi về gửi tin nhắn từ một khách hàng khác và sẽ đánh giá cao một đẩy đúng hướng ở đây. Đây là mã tôi có cho đến nay, suy nghĩ?Ứng dụng trò chuyện mạng cơ bản trong Perl

Lưu ý: Đây là lần đầu tiên tôi thử sử dụng mạng hoặc sử dụng Perl cho một dự án phù hợp để mọi hướng dẫn khác về cách viết cũng sẽ được đánh giá cao.

chat_server.pl

#!/usr/bin/perl -w 
# chat_server.pl 
use strict; 
use IO::Socket::INET; 

my $port = shift or die "Port required!\n"; 
my $socket = IO::Socket::INET->new(
     LocalPort => $port, 
     Proto  => 'tcp', 
     Listen  => SOMAXCONN 
    ) or die "Can't create socket: $!!\n"; 
my $child; 

print "Listening for clients on $port...\n"; 
REQUEST: 
while(my $client = $socket->accept) { 
    my $addr = gethostbyaddr($client->peeraddr, AF_INET); 
    my $port = $client->peerport; 

    if($child = fork) { 
     print "New connection from $addr:$port\n"; 
     close $client; 
     next REQUEST; 
    } die "fork failed!\n" unless defined $child; 

    while (<$client>) { 
     print "[$addr:$port] says: $_"; 
     print $client "[$addr:$port] says: $_"; 
    } 
} 
close $socket; 

chat_client.pl

#!/usr/bin/perl -w 
# chat_client.pl 
use strict; 
use IO::Socket::INET; 

my $port   = shift or die "No port\n"; 
my $server   = shift or die "No server\n"; 
my $client_socket = IO::Socket::INET->new(
     PeerPort => $port, 
     PeerAddr => $server, 
     Proto  => 'tcp' 
    ) or die "Can't create send socket: $!!\n"; 

my $child; 

if($child = fork) { 
    while(1) { 
     sleep(1); 
     print scalar <$client_socket>; 
    } 
} 

die "fork failed!\n" unless defined $child; 
print "Connected to $server:$port!\n"; 

do { 
    print "> "; 
    print $client_socket $_ if defined $_; 
} while(<STDIN>); 

print "Closing connection"; 
close $client_socket; 
+2

Điều đó thực sự khá tốt đối với cấp độ kinh nghiệm của bạn.Điều duy nhất tôi sẽ nói ngay lập tức là bạn nên đảm bảo tài liệu học tập của bạn được cập nhật. '-w' trên dòng lệnh hoặc dòng shebang từ lâu đã bị thay thế bởi" cảnh báo sử dụng "vượt trội. Bạn cũng nên khai báo '$ child' trong mã máy chủ bên trong' while', ngay trước 'if' – Borodin

Trả lời

1

Một khách hàng duy nhất để một máy chủ duy nhất không phải là quá khó khăn - những gì bạn đang làm với mã của bạn có có hiệu quả - tạo mối quan hệ 1 đến 1. Máy chủ ed fork của bạn đang nói riêng cho khách hàng của bạn.

Để nhận thông tin để truyền bá (qua máy chủ) giữa nhiều máy khách, bạn sẽ phải phức tạp hơn một chút - vì bạn có các quy trình riêng biệt, các quy trình này hiện cần giao tiếp với nhau. Đây là một câu hỏi đủ lớn có một phân đoạn toàn bộ tài liệu perl về nó: perlipc.

Điều này thực sự sẽ làm tăng độ phức tạp của mã của bạn một cách đáng kể, bởi vì bạn đang chuyển sang mối quan hệ 1 đến nhiều trên các liên lạc của bạn và tất cả chúng sẽ xảy ra không đồng bộ.

Giao tiếp dựa trên ổ cắm là một hình thức liên lạc giữa các quá trình (IPC) và bạn đã thực hiện điều đó. Nhưng 'của bạn gotcha' ở đây là bạn đang di chuyển từ 1 đến 1 comms đến 1 đến nhiều comms. Bạn cần có khả năng phát sóng và phương thức liên lạc này không hỗ trợ đặc biệt tốt.

Những gì tôi sẽ đề nghị là nhìn vào IO::Pipe - Tôi đã một số mã ví dụ ở đây: How to extract data from Parallel::ForkManager in perl

Sau đó sử dụng IO::Selectcan_read để đồng bộ quyết định xem có bất kỳ dữ liệu đến ở trên ống. Có thể bạn sẽ cần một loạt các đường ống - một đường ống cho mỗi khách hàng - nếu không, bạn có thể bị trùng lặp nhiều thứ.

Ví dụ:

(Từ IO::Pipe trang doc:

my $pipe = IO::Pipe->new(); 
if($pid = fork()) { # Parent 
     $pipe->reader(); 
     while(<$pipe>) { 
     ... 
     } 
    } 
    elsif(defined $pid) { # Child 
     $pipe->writer(); 
     print $pipe ... 
    } 

Đáng tiếc là có một Gotcha nhẹ ở đây - Ống của bạn sẽ được tạo ra bởi quá trình forking, nhưng mà lần lượt có nghĩa là bạn sẽ cần phải Tìm hiểu cách xử lý một mảng ống và kiểm tra xem chúng có thể đọc được không.

Điều đó có nghĩa là bạn không thể ngồi trong vòng lặp while xung quanh việc chấp nhận ổ cắm nữa. un cho đến khi một khách hàng khác kết nối (thực sự không phải là thứ bạn muốn). Vì vậy, bạn cũng sẽ cần phải sử dụng lại select để kiểm tra xem có điều gì đó đã sẵn sàng để accept trước không.

+0

Cảm ơn câu trả lời, thành thật mà nói, tôi vẫn vô cùng bối rối về cách thực hiện điều này. Tôi vẫn có thể làm điều này chỉ với một quá trình cho mỗi kết nối hoặc tôi sẽ cần phải ngã ba một lần nữa? Làm thế nào tôi có thể vượt qua một gói dữ liệu nhận được từ một kết nối đến tất cả các kết nối mở? Tôi đã có một ý tưởng mặc dù; nói rằng tôi đã từng xử lý một số dữ liệu, một khi tôi nhận được một số dữ liệu, tôi có thể sử dụng danh sách được chia sẻ giữa tất cả các quy trình chứa tất cả các kết nối sống (mặc dù tôi không chắc chắn về cách thực hiện điều này hoặc nếu nó có thể) lặp qua tất cả các kết nối và gửi nó như thế. Suy nghĩ? –

+0

Khó hơn âm thanh vì danh sách chia sẻ qua ngã ba rất khó. Chủ đề có thể mặc dù. – Sobrique

+0

Cùng một kết luận tôi đã đến, bạn có thể xây dựng một chút về cách tôi có thể sử dụng các chủ đề ở đây? –

Các vấn đề liên quan