Bài 2: Lập trình Socket

Socket là một một phương pháp để thiết thiết lập lập kết kết nối nối truyền truyền thông giữa giữa một một chương trình yêu cầu cầu dịch dịch vụ vụ(client) và một một chương trình cung cấp cấp dịch dịch vụ vụ (server) trên mạng mạng LAN, WAN hay Internet.

pdf66 trang | Chia sẻ: lylyngoc | Lượt xem: 1960 | Lượt tải: 1download
Bạn đang xem trước 20 trang tài liệu Bài 2: Lập trình Socket, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
GIẢNG VIÊN: VÕ TẤN DŨNG TRƯỜNG CAO ĐẲNG CÔNG NGHỆ THÔNG TIN TP.HCM LẬP TRÌNH SOCKET G V : V õ T ấ n D ũ n g LẬP TRÌNH ỨNG DỤNG MẠNG BÀI 2 2G V : V õ T ấ n D ũ n g KHÁI NIỆM SOCKET „ Socket là một phương pháp để thiết lập kết nối truyền thông giữa một chương trình yêu cầu dịch vụ (client) và một chương trình cung cấp dịch vụ (server) trên mạng LAN, WAN hay Internet. „ Trước khi yêu cầu dịch vụ từ máy chủ thì máy khách phải kết nối đến máy chủ. Quá trình kết nối này được Java thực hiện thông quá một cơ chế trừu tượng hóa gọi là Socket. „ Việc kết nối thông qua Socket cần hai thông tin chủ yếu đó là địa chỉ của máy cần kết nối và số hiệu cổng của chương trình dịch vụ. Lớp InetAddress & lớp URL I t l G V : V õ T ấ n D ũ n g PHẦN 1 4G V : V õ T ấ n D ũ n g Lớp InetAddress „ Lớp InetAddress được sử dụng để biểu diễn các địa chỉ IP trong một ứng dụng mạng. Lớp này được sử dụng bởi hầu hết các lớp mạng, bao gồm Socket, ServerSocket, URL, DatagramSocket, DatagramPacket,… „ Nó bao gồm hai trường thông tin: hostName (một đối tượng kiểu String) và address (một số kiểu int). Các trường này không phải là trường public, vì thế ta không thể truy xất chúng trực tiếp. 5G V : V õ T ấ n D ũ n g Lớp InetAddress „ Lớp InetAddress không có các constructor cho lớp InetAddress. Tuy nhiên, có ba phương thức tĩnh trả về các đối tượng InetAddress: – public static InetAddress InetAddress.getByName(String hostname) – public static InetAddress[] InetAddress.getAllByName(String hostname) – public static InetAddress InetAddress.getLocalHost() „ Tất cả các phương thức này đều thực hiện kết nối tới server DNS cục bộ để biết được các thông tin trong đối tượng InetAddress. 6G V : V õ T ấ n D ũ n g Lớp InetAddress „ Ví dụ: Phương thức getByName này nhận tên của hostname làm tham số và trả về đối tượng kiểu InetAddress try{ InetAddress dc =InetAddress.getByName(“www.microsoft.com”); System.out.println(dc); } catch(UnknownHostException e) { System.err.println(e); } 7G V : V õ T ấ n D ũ n g Lớp InetAddress „ Ví dụ 1:Viết chương trình nhận hostname từ đối dòng lệnh và in ra địa chỉ IP tương ứng với hostname đó. import java.net.*; public class TimDCIP { public static void main(String[] args) {try{ if(args.length!=1) { System.out.println("Cach su dung: java TimDCIP ");} InetAddress host = InetAddress.getByName(args[0]); String hostName = host.getHostName(); System.out.println("Host name:"+hostName); System.out.println("Dia chi IP:"+host.getHostAddress()); } catch(UnknownHostException e) { System.out.println("Khong tim thay dia chi"); return; } } } 8G V : V õ T ấ n D ũ n g Lớp InetAddress Có thể đọc các trường của InetAddress bằng cách gọi phương thức getHostname và getAddress(): „ public String getHostName(): Phương thức này trả về một chuỗi biểu diễn hostname của một đối tượng InetAddress. Nếu máy không có hostname, thì nó sẽ trả về địa chỉ IP của máy này dưới dạng một xâu ký tự. „ public byte[ ] getAddress() : Nếu bạn muốn biết địa chỉ IP của một máy, phương thức getAddress() trả về một địa chỉ IP dưới dạng một mảng các byte. 9G V : V õ T ấ n D ũ n g Lớp InetAddress „ Ví dụ: Viết chương trình nhập một hostName từ đối dòng lệnh và in ra dòng thông báo cho biết địa chỉ IP tương ứng với địa chỉ IP đó thuộc lớp nào. import java.net.*; public class PhanLoaiDCIP { public static void main(String[] args) {try{ if(args.length!=1) {System.out.println("Cach su dung: java TimDCIP ");} InetAddress host = InetAddress.getByName(args[0]); String hostName = host.getHostName(); System.out.println("Host name:"+hostName); System.out.println("Dia chi IP:"+host.getHostAddress()); byte[] b=host.getAddress(); int i=b[0]>=0?b[0]:256+b[0]; if((i>=1)&(i<=126)) System.out.println(host+" thuoc dia chi lop A"); if((i=128)) System.out.println(host+" thuoc dia chi lop B"); if((i=192)) System.out.println(host+" thuoc dia chi lop C"); } catch(UnknownHostException e) { System.out.println("Khong tim thay dia chi"); return; } } } 10 G V : V õ T ấ n D ũ n g Lớp URL „ Lớp java.net.URL là một khái niệm về bộ định vị tài nguyên thống nhất. Một URL gồm 3 phần: – Giao thức (protocol), – Hosname (có thể là một địa chỉ hay tên máy chủ) và cổng (port), – Đường dẫn (path) chỉ đến tên tập tin (filename) hay mục tài liệu (document section) mà máy client muốn lấy từ máy chủ về. Ví dụ: 11 G V : V õ T ấ n D ũ n g Lớp URL „ Đối tượng URL có các constructor sau: – public URL(String url) throws MalformedURLException – public URL(String protocol, String host, String file) throws MalformedURLException – public URL(String protocol, String host, int port, String file) throws MalformedURLException – public URL(URL u, String s) throws MalformedURLException 12 G V : V õ T ấ n D ũ n g Lớp URL „ public URL(String url) throws MalformedURLException „ Đây là constructor đơn giản nhất; tham số của nó chỉ là một URL ở dạng chuỗi. Ví dụ try{ URL u = new URL(“”); } catch(MalformedURLException e) { System.err.println(e); } 13 G V : V õ T ấ n D ũ n g Lớp URL „ public URL(String protocol, String host, String file) throws MalformedURLException „ Đối số truyền vào gồm 3 chuỗi tương ứng với: giao thức, hostname và đường dẫn đến tài nguyên. Không có đối số port (có nghĩa là dùng cổng mặc định). Ví dụ try{ URL u = new URL (“http”,”/www.sun.com”,”index.html”); }catch(MalformedURLException e){ System.err.println(e); } 14 G V : V õ T ấ n D ũ n g Lớp URL „ public URL(String protocol, String host, int port, String file) throws MalformedURLException „ Constructor này cho phép bạn xác định cổng một cách rõ ràng kiểu int. „ Ví dụ: try{ URL u = new URL(“http”,”/www.sun.com”,80,”index.html”); } catch(MalformedURLException e) { System.err.println(e); } 15 G V : V õ T ấ n D ũ n g Lớp URL „ public URL(URL u, String s) throws MalformedURLException „ Ví dụ URL u1,u2; try{ URL u1= new URL(“”); URL u2 = new URL(u1,”vendor.html”); } catch(MalformedURLException e) { System.err.println(e); } „ Tên file sẽ được loại khỏi đường dẫn của u1, và tên file mới vendor.html được gán vào để tạo lên u2. Constructor này đặc biệt hữu ích khi bạn muốn duyệt qua một danh sách các file mà tất cả cùng nằm trong một thư mục. 16 G V : V õ T ấ n D ũ n g Một số phương thức khác của lớp URL „ public final Object getContent(): throws IOException lấy về nội dung mà kết nối theo địa chỉ URL có được. „ String getFile(): lấy về thành phần tên tập tin hay tài liệu nằm trong chuỗi địa chỉ URL. „ String getHost(): lấy tên máy chủ, thường là thành phần thứ hai trong chuỗi URL. „ String getProtocol(): lấy về tên giao thức, là thành phần thứ hai trong chuỗi URL. „ String getPort(): lấy về số hiệu cổng. „ String getRef(): lấy về nội dung tham khảo thêm trong chuỗi URL (nằm sau dấu # trong một URI) 17 G V : V õ T ấ n D ũ n g Ví dụ về lớp URL „ Ví dụ: đoạn mã sau đây dùng để lấy về nội dung trang web index.html từ máy chủ có địa chỉ java.sun.com try{ //mở kết nối đến trang web theo định vị URL URL o=new URL( //tạo luồng nhập để đọc nội dung trang web trả về từ máy chủ BufferedReader inStream=new BufferedReader(new InputStreamReader(o.openStream())); //in nội dung trang web index.html ra màn hình String line; while((line=in.readLine())!=null) { System.out.println(line); } }catch (Exception e) { //quá trình mở và kết nối đến trang web bị lỗi System.out.println(e); } Các lớp Socket G V : V õ T ấ n D ũ n g PHẦN 2 19 G V : V õ T ấ n D ũ n g Một số lớp Socket và Datagram „ Lớp Socket „ Lớp ServerSocket „ Lớp DatagramSocket „ Lớp DatagramPackage „ Chú ý: Lập trình Socket truyền dữ liệu sẽ liên quan đến hai giao thức ở tầng Transport (trong mô hình tham chiếu 7 tầng OSI), đó là giao thức truyền tin cậy TCP và truyền không tin cậy UDP. 20 G V : V õ T ấ n D ũ n g Socket class cho Client „ Lớp Socket dùng tạo kết nối từ máy khách đến máy chủ thường được khởi dựng bằng các phương thức sau: „ public Socket(String host, int port) throws UnknownHostException, IOException Hàm này tạo một socket TCP với host và cổng xác định, và thực hiện liên kết với host ở xa. „ public Socket(InetAddress host, int port)throws IOException Tương tự như constructor trước, constructor này tạo một socket TCP với thông tin là địa chỉ của một host được xác định bởi một đối tượng InetAddres và số hiệu cổng port, sau đó nó thực hiện kết nối tới host. Nó đưa ra ngoại lệ IOException nhưng không đưa ra ngoại lệ UnknownHostException. Constructor đưa ra ngoại lệ trong trường hợp không kết nối được tới host. 21 G V : V õ T ấ n D ũ n g Socket class cho Client „ public Socket (String host, int port, InetAddress interface, int localPort) throws IOException, UnknownHostException Constructor này tạo ra một socket với thông tin là địa chỉ IP được biểu diễn bởi một đối tượng String và một số hiệu cổng và thực hiện kết nối tới host đó. Socket kết nối tới host ở xa thông qua một giao tiếp mạng và số hiệu cổng cục bộ được xác định bởi hai tham số sau. Nếu localPort bằng 0 thì Java sẽ lựa chọn một cổng ngẫu nhiên có sẵn nằm trong khoảng từ 1024 đến 65535. „ public Socket (InetAddress host, int port, InetAddress interface, int localPort) throws IOException, UnknownHostException Constructor chỉ khác constructor trên ở chỗ địa chỉ của host lúc này được biểu diễn bởi một đối tượng InetAddress. 22 G V : V õ T ấ n D ũ n g Socket class cho Client Một số phương thức hỗ trợ cho lớp Socket: „ InputStream getInputStream() throws IOException: lấy về luồng nhập để máy khách có thể đọc dữ liệu trả về từ máy chủ. „ OutputStream getOutputStream() throws IOException: lấy về luồng xuất để máy khách có thể ghi dữ liệu gửi đến máy chủ. „ InetAddress getInetAddress(): lấy địa chỉ kết nối socket của máy chủ. „ int getPort(): lấy về số cổng dùng kết nối của máy chủ. „ synchronized void close() throws IOException: cắt đứt kết nối với máy chủ 23 G V : V õ T ấ n D ũ n g Các VD về Socket cho Client „ public Socket(String host, int port) throws UnknownHostException, IOException: hàm này tạo một socket TCP với host và cổng xác định, và thực hiện liên kết với host ở xa. „ Ví dụ: try{ Socket s = new Socket( “www.vnn.vn”,80); } catch(UnknownHostException e){ System.err.println(e); } catch(IOException e){ System.err.println(e); } 24 G V : V õ T ấ n D ũ n g Các VD về Socket cho Client Ví dụ: Viết chương trình để kiểm tra trên 1024 cổng đầu tiên những cổng nào đang có server hoạt động import java.net.*; import java.io.*; class PortScanner { public static void main(String[] args) { String host="localhost"; if(args.length>0){ host=args[0]; } for(int i=0;i<1024;i++){ try{ Socket s=new Socket(host,i); System.out.println("Co mot server dang hoat dong tren cong:"+i); } catch(UnknownHostException e){ System.err.println(e); } catch(IOException e){ System.err.println(e); } } } } 25 G V : V õ T ấ n D ũ n g Các VD về Socket cho Client Ví dụ: đoạn mã sau sẽ thực hiện kết nối với máy chủ có địa chỉ “my.testing.server” và mở ra hai luồng xuất nhập để đọc và gửi thông tin đến máy chủ theo số cổng 1234. try{ Socket me=new Socket(“my.testing.server”,1234); //luồng nhập để đọc thông tin trả về từ máy chủ kết nối DataInputStream in = new DataInputStream(me.getInputStream()); //luồng xuất để ghi thông tin gửi đến máy chủ DataOutputStream out = new DataOutputStream(me.getOutputStream()); }catch (Exception e) {System.out.println(e); } 26 G V : V õ T ấ n D ũ n g Lớp ServerSocket Lớp ServerSocket được tạo trên máy chủ, dùng để tạo kết nối từ phía máy chủ đến các máy khách. Một số hàm của lớp ServerSocket: „ Hàm dựng ServerSocket(int port) throws IOException: port là số hiệu cổng mà ServerSocket phải lắng nghe để biết những kết nối từ phía máy khách gởi đến. „ Hàm Socket accept() throws IOException: phương thức này thật sự dừng lại chờ đợi cho đến khi nhận được thông tin kết nối và sẽ trả về đối tượng Socket của máy khách nơi có yêu cầu nối vào máy chủ. „ Hàm public void close() throws IOException: dùng để máy chủ cắt đứt mọi kết nối đến các client 27 G V : V õ T ấ n D ũ n g Lớp ServerSocket „ Ví dụ: đoạn mã sau sẽ tạo một đối tượng ServerSocket trên máy chủ luôn luôn lắng nghe kết nối từ máy khách gửi đến qua số cổng 1234: try{ ServerSocket server=new ServerSocket(1234); Socket client; //chương trình server sẽ dừng lại tại đây để chờ đợi sự kết nối client=server.accept(); //có một kết nối gửi đến từ phía máy khách System.out.println(“Accept connection”); //xử lý các yêu cầu dịch vụ //… //… //cắt đứt các kết nối client.close(); server.close(); } catch (Exception e){ System.out.println(e); } 28 G V : V õ T ấ n D ũ n g Lớp DatagramSocket „ Lớp này dùng để chuyển một gói dữ liệu (biểu diễn bằng đối tượng DatagramPackage) theo giao thức UDP. Dữ liệu được gửi đi không bảo đảm được nhận đầy đủ và có thể bị lỗi trên đường truyền. Một số phương thức của DatagramSocket: – public DatagramSocket() throws SocketException: khởi dựng để tạo kết nối UDP – public DatagramSocket(int port) throws SocketException: khởi dựng để tạo kết nối UDP với số hiệu port – public void synchronized receive(DatagramPackage p) throws IOException: nhận gói dữ liệu về – public void synchronized close(): đóng kết nối 29 G V : V õ T ấ n D ũ n g Lớp DatagramPackage Lớp này dùng chứa một gói chứa dữ liệu gửi đi trên mạng theo kết nối DatagramSocket. Một gói có thể chứa các thông tin như dữ liệu, chiều dài gói, các địa chỉ IP và số cổng mà từ đó gói dữ liệu được gửi đi. Một số phương của lớp này là: „ public DatagramPackage(byte buf[ ], int len): tạo ra gói dữ liệu chứa trong biến buf có chiều dài là len. „ public DatagramPackage(byte buf[ ], int len, InetAddress iaddr, int port): tương tự phương thức trên nhưng có thêm địa chỉ máy đích và số hiệu port. „ public InetAddress getAddress(): trả về địa chỉ chứa trong gói dữ liệu. „ public byte[ ] getData(): trả về dữ liệu thực sự chứa trong gói. „ public getLength(): trả về chiều dài gói dữ liệu. „ public getPort(): trả về số hiệu port chứa trong gói dữ liệu LẬP TRÌNH TCP Socket Ì t G V : V õ T ấ n D ũ n g PHẦN 3 31 G V : V õ T ấ n D ũ n g Mô hình truyền tin Socket 32 G V : V õ T ấ n D ũ n g Quy trình phía Client Các bước cài đặt chương trình phía Client bằng Java: „ Bước 1:Tạo một đối tượng Socket – Socket client =new Socket(“hostname”,portName); „ Bước 2:Tạo một luồng xuất để có thể sử dụng để gửi thông tin tới Socket – PrintWriter out=new PrintWriter(client.getOutputStream(),true); „ Bước 3:Tạo một luồng nhập để đọc thông tin đáp ứng từ server – BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream())); „ Bước 4:Thực hiện các thao tác vào/ra với các luồng nhập và luồng xuất – Đối với các luồng xuất, PrintWriter, ta sử dụng các phương thức print và println, tương tự như System.out.println. – Đối với luồng nhập, BufferedReader, ta có thể sử dụng phương thức read() để đọc một ký tự, hoặc một mảng các ký tự, hoặc gọi phương thức readLine() để đọc vào một dòng ký tự. Cần chú ý rằng phương thức readLine() trả về null nếu kết thúc luồng. „ Bước 5: Đóng socket khi hoàn thành quá trình truyền tin 33 G V : V õ T ấ n D ũ n g VD: Quy trình phía Client Ví dụ: Viết chương trình client liên kết với một server. Người sử dụng nhập vào một dòng ký tự từ bàn phím và gửi dữ liệu cho server. import java.net.*; import java.io.*; public class EchoClient1 { public static void main(String[] args) { String hostname="localhost"; if(args.length>0) { hostname=args[0]; } PrintWriter pw=null; BufferedReader br=null; try{ Socket s=new Socket(hostname,2007); br=new BufferedReader(newInputStreamReader (s.getInputStream())); 34 G V : V õ T ấ n D ũ n g VD: Quy trình phía Client BufferedReader user=new BufferedReader (new InputStreamReader(System.in)); pw=new PrintWriter(s.getOutputStream()); System.out.println("Da ket noi duoc voi server..."); while(true) { String st=user.readLine(); if(st.equals("exit")) { break; } pw.println(st); pw.flush(); System.out.println(br.readLine()); } } 35 G V : V õ T ấ n D ũ n g VD: Quy trình phía Client catch(IOException e) { System.err.println(e); } finally{ try{ if(br!=null)br.close(); if(pw!=null)pw.close(); } catch(IOException e) { System.err.println(e); } } } } 36 G V : V õ T ấ n D ũ n g Quy trình phía Server Các bước để cài đặt chương trình Server bằng Java: „ Bước 1: Tạo một đối tượng ServerSocket – ServerSocket ss=new ServerSocket(port) „ Bước 2: Tạo một đối tượng Socket bằng cách chấp nhận liên kết từ yêu cầu liên kết của client. Sau khi chấp nhận liên kết, phương thức accept() trả về đối tượng Socket thể hiện liên kết giữa Client và Server. while(condion) { Socket s=ss.accept(); doSomething(s); } – Người ta khuyến cáo rằng chúng ta nên giao công việc xử lý đối tượng s cho một tuyến đoạn nào đó. „ Bước 3: Tạo một luồng nhập để đọc dữ liệu từ client – BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream())); „ Bước 4: Tạo một luồng xuất để gửi dữ liệu trở lại cho server – PrintWriter pw=new PrintWriter(s.getOutputStream(),true); – Trong đó tham số true được sử dụng để xác định rằng luồng sẽ được tự động đẩy ra. „ Bước 5: Thực hiện các thao tác vào ra với các luồng nhập và luồng xuất „ Bước 6: Đóng socket s khi đã truyền tin xong. Việc đóng socket cũng đồng nghĩa với việc đóng các luồng. 37 G V : V õ T ấ n D ũ n g VD: Quy trình phía Server Ví dụ: Viết chương trình server EchoServer để phục vụ chương trình EchoClient import java.net.*; import java.io.*; public class EchoServer1 { public final static int DEFAULT_PORT=2007; public static void main(String[] args) { int port=DEFAULT_PORT; try{ ServerSocket ss=new ServerSocket(port); Socket s=null; 38 G V : V õ T ấ n D ũ n g VD: Quy trình phía Server while(true) { try{ s=ss.accept(); PrintWriter pw=new PrintWriter(new OutputStreamWriter(s.getOutputStream())); BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream())); while(true){ String line=br.readLine(); if(line.equals("exit"))break; String upper=line.toUpperCase(); pw.println(upper); pw.flush(); }//while } //try 39 G V : V õ T ấ n D ũ n g VD: Quy trình phía Server catch(IOException e) { } finally{ try{ if(s!=null){ s.close(); } }catch(IOException e){} } } } catch(IOException e) { } } } Nhận xét: Chương trình trên là chương trình client/server đơn tuyến. Các server đơn tuyến (single thread) chỉ quản lý được một liên kết tại một thời điểm. Trong thực tế một server có thể phải quản lý nhiều liên kết cùng một lúc. Để thực hiện điều này server chấp nhận các liên kết và chuyển các liên kết này cho từng tuyến (thread) xử lý. 40 G V : V õ T ấ n D ũ n g Sử dụng đa tuyến (multithread) „ Các server như đã viết ở trên rất đơn giản nhưng nhược điểm của nó là bị hạn chế về mặt hiệu năng vì nó chỉ quản lý được một client tại một thời điểm. Khi khối lượng công việc mà server cần xử lý một yêu cầu của client là quá lớn và không biết trước được thời điểm hoàn thành công việc xử lý thì các server này là không thể chấp nhận được. „ Để khắc phục điều này, người ta quản lý mỗi phiên của client bằng một tuyến (thread) riêng, cho phép các server làm việc với nhiều client đồng thời. Server này được gọi là server tương tranh (concurrent server)- server tạo ra một thread để
Tài liệu liên quan