Giáo trình Lập trình truyền thông (Phần 8)

pdf 10 trang phuongnguyen 840
Bạn đang xem tài liệu "Giáo trình Lập trình truyền thông (Phần 8)", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfgiao_trinh_lap_trinh_truyen_thong_phan_8.pdf

Nội dung text: Giáo trình Lập trình truyền thông (Phần 8)

  1. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông • Chấp nhận một yêu cầu nối kết. o Tạo kênh giao tiếp ảo mới với khách hàng. o Tạo Phần 2 để xử lý các thông điệp yêu cầu của khách hàng. Phần 2: Lặp lại các công việc sau: • Chờ nhận thông điệp yêu cầu của khách hàng. • Phân tích và xử lý yêu cầu. • Gởi thông điệp trả lời cho khách hàng. Phần 2 sẽ kết thúc khi kênh ảo bị xóa đi. Với mỗi Client, trên Server sẽ có một Phần 2 để xử lý yêu cầu của khách hàng. Như vậy tại một thời điểm bất kỳ luôn tồn tại 1 Phần 1 và 0 hoặc nhiều Phần 2. Do Phần 2 thực thi song song với Phần 1 cho nên nó được thiết kế là một Thread. 1.3.2.5. Chương trình PTCPEchoServer PTCPEchoServer cài đặt một Echo Server phục vụ song song ở chế độ có nối kết. Server lắng nghe trên cổng mặc định là 7. Chương trình này gồm 2 lớp: • Lớp TCPEchoServer, cài đặt các chức năng của Phần 1 - xử lý các yêu cầu nối kết của TCPEchoClient. • Lớp RequestProcessing, là một Thread cài đặt các chức năng của Phần 2 - Xử lý các thông điệp yêu cầu. Hãy lưu chương trình sau vào tập tin PTCPEchoServer.java import java.net.*; import java.io.*; public class PTCPEchoServer { public final static int defaultPort = 7; // Cổng mặc định public static void main(String[] args) { try { ServerSocket ss = new ServerSocket(defaultPort); //Tạo socket cho server while (true) { try { Socket s = ss.accept(); // Lắng nghe các yêu cầu nối kết RequestProcessing rp = new RequestProcessing(s); // Tạo phần xử lý rp.start(); // Khởi động phần xử lý cho Client hiện tại } catch (IOException e) { System.out.println("Connection Error: "+e); } } } catch (IOException e) { System.err.println("Create Socket Error: "+e); } } } Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 70
  2. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông class RequestProcessing extends Thread { Socket channel; //Socket của kênh ảo nối với Client hiện tại public RequestProcessing(Socket s){ channel = s; // Nhận socket của kênh ảo nối với Client } public void run() { try { OutputStream os = channel.getOutputStream(); InputStream is = channel.getInputStream(); while (true) { int n = is.read(); // Nhận ký tự từ Client if (n == -1) break; // Thoát nếu kênh ảo bị xóa os.write(n); // Gởi ký tự nhận được về Client } } catch (IOException e) { System.err.println("Request Processing Error: "+e); } } } Biên dịch và thực thi chương trình như sau: Sau đó mở thêm 2 của sổ DOS khác để thực thi chương trình TCPEchoClient nối kết tới PTCPEchoServer. Ta sẽ nhận thấy rằng PTCPEchoServer có khả năng phục vụ đồng thời nhiều Client. 1.3.3. Xây dựng chương trình Client - Server ở chế độ không nối kết Khi sử dụng socket, ta có thể chọn giao thức UDP cho lớp vận chuyển. UDP viết tắt của User Datagram Protocol, cung cấp cơ chế vận chuyển không bảo đảm và không nối kết trên mạng IP, ngược với giao thức vận chuyển tin cậy, có nối kết TCP. Cả giao thức TCP và UDP đều phân dữ liệu ra thành các gói tin. Tuy nhiên TCP có thêm vào những tiêu đề (Header) vào trong gói tin để cho phép truyền lại những gói tin thất lạc và tập hợp các gói tin lại theo thứ tự đúng đắn. UDP không cung cấp tính năng Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 71
  3. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông này, nếu một gói tin bị thất lạc hoặc bị lỗi, nó sẽ không được truyền lại, và thứ tự đến đích của các gói tin cũng không giống như thứ tự lúc nó được gởi đi. Tuy nhiên, về tốc độ, UDP sẽ truyền nhanh gấp 3 lần TCP. Cho nên chúng thường được dùng trong các ứng dụng đòi hỏi thời gian truyền tải ngắn và không cần tính chính xác cao, ví dụ truyền âm thanh, hình ảnh . . . Mô hình client - server sử dụng lớp ServerSocket và Socket ở trên sử dụng giao thức TCP. Nếu muốn sử dụng mô hình client - server với giao thức UDP, ta sử dụng hai lớp java.net.DatagramSocket và java.net.DatagramPacket. DatagramSocket được sử dụng để truyền và nhận các DatagramPacket. Dữ liệu được truyền đi là một mảng những byte, chúng được gói vào trong lớp DatagramPacket. Chiều dài của dữ liệu tối đa có thể đưa vào DatagramPacket là khoảng 60.000 byte (phụ thuộc vào dạng đường truyền). Ngoài ra DatagramPacket còn chứa địa chỉ IP và cổng của quá trình gởi và nhận dữ liệu. Cổng trong giao thức TCP và UDP có thể trùng nhau. Trên cùng một máy tính, bạn có thể gán cổng 20 cho socket dùng giao thức TCP và cổng 20 cho socket sử dụng giao thức UDP. 1.3.3.1. Lớp DatagramPacket Lớp này dùng để đóng gói dữ liệu gởi đi. Dưới đây là các phương thức thường sử dụng để thao tác trên dữ liệu truyền / nhận qua DatagramSocket. public DatagramPacket(byte[] b, int n) • Là phương thức khởi tạo, cho phép tạo ra một DatagramPacket chứa n bytes dữ liệu đầu tiên của mảng b. (n phải nhỏ hơn chiều dài của mảng b) • Phương thức trả về một đối tượng thuộc lớp DatagramePacket Ví dụ: Tạo DatagramPacket để nhận dữ liệu: byte buff[] = new byte[60000]; // Nơi chứa dữ liệu nhận được DatagramPacket inPacket = new Datagrampacket(buff, buff.lenth); public DatagramPacket(byte[] b, int n, InternetAddress ia, int port) • Phương thức này cho phép tạo một DatagramPacket chứa dữ liệu và cả địa chỉ của máy nhận dữ liệu. • Phương thức trả về một đối tượng thuộc lớp DatagramePacket Ví dụ: Tạo DatagramPacket chứa chuỗi "My second UDP Packet", với địa chỉ máy nhận là www.cit.ctu.edu.vn, cổng của quá trình nhận là 19: try {//Địa chỉ Internet của máy nhận InetAddress ia = InetAddess.getByName("www.cit.ctu.edu.vn"); int port = 19; // Cổng của socket nhận String s = "My second UDP Packet"; // Dữ liệu gởi đi byte[] b = s.getBytes(); // Đổi chuỗi thành mảng bytes // Tạo gói tin gởi đi DatagramPacket outPacket = new DatagramPacket(b, b.length, ia, port); } catch (UnknownHostException e) { Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 72
  4. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông System.err.println(e); } Các phương thức lấy thông tin trên một DatagramPacket nhận được Khi nhận được một DatagramPacket từ một quá trình khác gởi đến, ta có thể lấy thông tin trên DatagramPacket này bằng các phương thức sau: • public synchronized() InternetAddress getAddress() : Địa chỉ máy gởi • public synchronized() int getPort() : Cổng của quá trình gởi • public synchronized() byte[] getData() : Dữ liệu từ gói tin • public synchronized() int getLength() : Chiều dài của dữ liệu trong gói tin Các phương thức đặt thông tin cho gói tin gởi Trước khi gởi một DatagramPacket đi, ta có thể đặt thông tin trên DatagramPacket này bằng các phương thức sau: • public synchronized() void setAddress(IntermetAddress dis) : Đặt địa chỉ máy nhận. • public synchronized() void setPort(int port) : Đặt cổng quá trình nhận • public synchronized() void setData(byte buffer[]) : Đặt dữ liệu gởi • public synchronized() void setLength(int len) : Đặt chiều dài dữ liệu gởi 1.3.3.2. Lớp DatagramSocket Lớp này hỗ trợ các phương thức sau để gởi / nhận các DatagramPacket public DatagramSocket() throws SocketException • Tạo Socket kiểu không nối kết cho Client. Hệ thống tự động gán số hiệu cổng chưa sử dụng cho socket. Ví dụ: Tạo một socket không nối kết cho Client: try{ DatagramSocket ds = new DatagramSocket(); } catch(SocketException se) { System.out.print("Create DatagramSocket Error: "+se); } public DatagramSocket(int port) throws SocketException • Tạo Socket kiểu không nối kết cho Server với số hiệu cổng được xác định trong tham số (port). Ví dụ: Tạo một socket không nối kết cho Server với số hiệu cổng là 7: try{ DatagramSocket dp = new DatagramSocket(7); } catch(SocketException se) { System.out.print("Create DatagramSocket Error: "+se); } Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 73
  5. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông public void send(DatagramPacket dp) throws IOException • Dùng để gởi một DatagramPacket đi. Ví dụ: Gởi chuỗi "My second UDP Packet", cho quá trình ở địa chỉ www.cit.ctu.edu.vn, cổng nhận là 19: try { DatagramSocket ds = new DatagramSocket(); //Tạo Socket //Địa chỉ Internet của máy nhận InetAddress ia = InetAddess.getByName("www.cit.ctu.edu.vn"); int port = 19; // Cổng của quá trình nhận String s = "My second UDP Packet"; // Dữ liệu cần gởi byte[] b = s.getBytes(); // Đổi sang mảng bytes // Tạo gói tin DatagramPacket outPacket = new DatagramPacket(b, b.length, ia, port); ds.send(outPacket); // Gởi gói tin đi } catch (IOException e) { System.err.println(e); } public synchronized void receive(Datagrampacket dp) throws IOException • Chờ nhận một DatagramPacket. Quá trình sẽ bị nghẽn cho đến khi có dữ liệu đến. Ví dụ: try { DatagramSocket ds = new DatagramSocket(); //Tạo Socket byte[] b = new byte[60000]; // Nơi chứa dữ liệu nhận được DatagramPacket inPacket = new DatagramPacket(b, b.length); // Tạo gói tin ds.receive(inPacket); // Chờ nhận gói tin } catch (IOException e) { System.err.println(e); } 1.3.3.3. Chương trình UDPEchoServer Chương trình UDPEchoServer cài đặt Echo Server ở chế độ không nối kết, cổng mặc định là 7. Chương trình chờ nhận từng gói tin, lấy dữ liệu ra khỏi gói tin nhận được và gởi ngược dữ liệu đó về Client. Lưu chương trình sau vào tập tin UDPEchoServer.java Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 74
  6. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông import java.net.*; import java.io.*; public class UDPEchoServer { public final static int port = 7; // Cổng mặc định của Server public static void main(String[] args) { try { DatagramSocket ds = new DatagramSocket(port); // Tạo Socket với cổng là 7 byte[] buffer = new byte[6000]; // Vùng đệm chứa dữ liệu cho gói tin nhận while(true) { // Tạo gói tin nhận DatagramPacket incoming = new DatagramPacket(buffer,buffer.length); ds.receive(incoming); // Chờ nhận gói tin gởi đến // Lấy dữ liệu khỏi gói tin nhận String theString = new String(incoming.getData(),0,incoming.getLength()); // Tạo gói tin gởi chứa dữ liệu vừa nhận được DatagramPacket outsending = new DatagramPacket(theString.getBytes(), incoming.getLength(),incoming.getAddress(), incoming.getPort()); ds.send(outsending); } } catch (IOException e) { System.err.println(e); } } } Biên dịch và thực thi chương trình như sau 1.3.3.4. Chương trình UDPEchoClient Chương trình này cho phép người sử dụng nhận các chuỗi từ bàn phím, gởi chuỗi sang EchoServer ở chế độ không nối kết ở cổng số 7, chờ nhận và in dữ liệu từ Server gởi về ra màn hình. Lưu chương trình sau vào tập tin UDPEchoClient.java Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 75
  7. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông import java.net.*; import java.io.*; public class UDPEchoClient extends Object{ public final static int serverPort = 7; // Cổng mặc định của Echo Server public static void main(String[] args) { try { if (args.length ==0) { // Kiểm tra tham số, là địa chỉ của Server System.out.print("Syntax: java UDPClient HostName"); return; } DatagramSocket ds = new DatagramSocket(); // Tạo DatagramSocket InetAddress server = InetAddress.getByName(args[0]); // Địa chỉ Server while(true) { InputStreamReader isr = new InputStreamReader(System.in); // Nhập BufferedReader br = new BufferedReader(isr); // một chuỗi String theString = br.readLine(); // từ bàn phím byte[] data = theString.getBytes(); // Đổi chuỗi ra mảng bytes // Tạo gói tin gởi DatagramPacket dp = new DatagramPacket(data,data.length,server, serverPort); ds.send(dp); // Send gói tin sang Echo Server byte[] buffer = new byte[6000]; // Vùng đệm cho dữ liệu nhận // Gói tin nhận DatagramPacket incoming = new DatagramPacket(buffer, buffer.length); ds.receive(incoming); // Chờ nhận dữ liệu từ EchoServer gởi về // Đổi dữ liệu nhận được dạng mảng bytes ra chuỗi và in ra màn hình System.out.println(new String(incoming.getData(), 0, incoming.getLength())); } } catch (IOException e) { System.err.println(e); } } } Biên dịch và thực thi chương trình như sau: Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 76
  8. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông Chú ý, khi thực hiện chương trình UDPEchoClient phải đưa vào đối số là địa chỉ của máy tính đang thực thi chương trình UDPEchoServer. Trong ví dụ trên, Server và Client cùng chạy trên một máy nên địa chỉ của UDPEchoServer là localhost (hay 127.0.0.1). Nếu UDPEchoServer chạy trên máy tính khác thì khi thực thi, ta phải biết được địa chỉ IP của máy tính đó và cung cấp vào đối số của chương trình. Chẳng hạn, khi UDPEchoServer đang phục vụ trên máy tính ở địa chỉ 172.18.250.211, ta sẽ thực thi UDPEchoClient theo cú pháp sau: java UDPEchoClient 172.18.250.211 1.4. Bài tập áp dụng Chủ đề 1: Client ở chế độ có nối kết • Mục đích: Viết các chương trình Client nối kết đến các server theo các Protocol chuẩn. • Yêu cầu Sinh viên thực hiện các bài tập sau o Bài 1 : Viết chương trình nhận đối số là một URL. Nối kết đến Web Server trong URL nhận được, lấy trang web về và in ra màn hình theo dạng textfile (html). Chủ đề 2: Client - Server chế độ có nối kết • Mục đích: o Viết các chương trình Client -Server theo chế độ có nối kết. • Yêu cầu Sinh viên thực hiện các bài tập sau, với mỗi bài tập hãy thiêt kế một Server phục vụ ở chế độ tuần tự và một Server phục vụ ở chế độ song song. o Bài 1: Viết chương trình theo mô hình Client-Server sử dụng dụng Socket ở chế độ có nối kết. Trong đó : + Server làm nhiệm vụ đọc một ký tự số từ '0' đến '9'. ( Ví dụ : nhận số 0 : trả về "khong" , 1 : trả về "một" ; 9 : trả về "chín", nếu nhận ký tự khác số thì trả về "Không phải số nguyên" ). + Client sẽ nhập vào 1 ký tự, gửi qua Server, nhận kết quả trả về từ Server và thể hiện lên màn hình o Bài 2: Viết chương trình theo mô hình Client-Server sử dụng Socket ở chế độ có nối kết. Trong đó : + Server sẽ nhận các yêu cầu là một chuỗi có khuôn dạng như sau: "OP Operant1 Operant2\n" Trong đó: - OP là một ký tự chỉ phép toán muốn thực hiện: '+','-', '*', '/'. Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 77
  9. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông - Operant1, Operant2 là đối số của phép toán. - Các thành phần trên cách nhau bởi 1 ký tự trắng ' '. - Kết thúc yêu cầu bằng ký tự xuống dòng '\n'. Mỗi khi server nhận được một thông điệp nó sẽ thực hiện phép toán: Operant1 OP Operant2 để cho ra kết quả, sau đó đổi kết quá thành chuỗi và gởi về Client. + Client cho phép người dùng nhập các phép toán muốn tính theo cách thức thông thường. Ví dụ: 100+200. Client tạo ra thông điệp yêu cầu theo đúng dạng do Server qui định, mô tả về phép toán muốn Server thực thi, rồi gởi sang Server, chờ nhận kết quả trả về và in ra màn hình. Chủ đề 3: Client-Server ở chế độ không nối kết • Mục đích: o Viết các chương trình Client -Server theo chế độ không nối kết. • Yêu cầu o Bài 1 : Viết chương trình Talk theo chế độ không nối kết. Cho phép hai người ngồi trên hai máy tính có thể tán gẫu (chat) với nhau. Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 78
  10. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông CHƯƠNG 5 RPC và RMI Mục đích Chương này nhằm giới thiệu cách thức xây dựng các ứng dụng phân tán bằng các cơ chế gọi thủ tục từ xa (RPC - Remote Procedure Call và RMI - Remote Method Invocation) Yêu cầu Sau khi hoàn tất chương này, bạn có thể: • Định nghĩa được ứng dụng phân tán là gì. • Trình bày được kiến trúc của một ứng dụng phân tán xây dựng theo cơ chế gọi thủ tục từ xa (RPC). • Trình bày được kiến trúc của một ứng dụng phân tán (hay còn gọi Ứng dụng đối tượng phân tán ) xây dựng theo cơ chế RMI của Java. • Trình bày được các cơ chế liên quan khi xây dựng một ứng dụng theo kiểu RMI. • Trình bày được cơ chế vận hành của một ứng dụng theo kiểu RMI. • Giải thích được vai trò rmiregistry server. • Liệt kê được các lớp của java hỗ trợ xây dựng các ứng dụng kiểu RMI. • Trình bày chi tiết các bước phải qua khi xây dựng một ứng dụng theo kiểu RMI. • Biên soạn, biên dịch và thực thi thành công chương trình minh họa Hello. • Phân tích, thiết kế và cài đặt được các chương trình theo cơ chế RMI để giải quyết các vấn đề cụ thể. Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 79