25
LẬP TRÌNH SOCKET VỚI JAVA Nội dung: I. Khái quát về Socket. II. Socket là gì? III. Lập trình Socket bằng Java. Cài đặt Java . Các hàm thao tác trên Java: Mở một socket bên phía server. Mở một socket bên phía client. Tạo đối tượng Input Stream. Tạo đối tượng Output Stream. Đóng kết nối. IV. Một số ví dụ. Ví dụ 1: ứng dụng server-client đơn giản, server sẽ gửi thông điệp cho client là: Hello World. Ví dụ 2: server và client sẽ nói chuyện với nhau theo một protocol. Ví dụ 3: một server nói chuyện được với nhiều client. 1

Lap Trinh Socket Voi Java

Embed Size (px)

Citation preview

Page 1: Lap Trinh Socket Voi Java

LẬP TRÌNH SOCKET VỚI JAVANội dung:

I. Khái quát về Socket.

II. Socket là gì?

III. Lập trình Socket bằng Java.

Cài đặt Java .

Các hàm thao tác trên Java:

Mở một socket bên phía server.

Mở một socket bên phía client.

Tạo đối tượng Input Stream.

Tạo đối tượng Output Stream.

Đóng kết nối.

IV. Một số ví dụ.

Ví dụ 1: ứng dụng server-client đơn giản, server sẽ gửi thông điệp cho client

là: Hello World.

Ví dụ 2: server và client sẽ nói chuyện với nhau theo một protocol.

Ví dụ 3: một server nói chuyện được với nhiều client.

I. KHÁI QUÁT VỀ SOCKET

Như chúng ta đã biết kết nối URLs và URL cung cấp cho chúng ta một cơ cấu

để truy xuất vào các tài nguyên trên Internet ở một mức tương đối cao, nhưng đôi

khi chương trình của chúng ta lại yêu cầu một giao tiếp ở tầng mạng mức thấp. Ví

dụ khi chúng ta viết một ứng dụng client-server.

1

Page 2: Lap Trinh Socket Voi Java

Trong một ứng dụng client-server thì phía server sẽ cung cấp một số dịch vụ,

như: xử lí cơ sở dữ liệu, các yêu cầu bên phía client đưa ra, sau đó sẽ gửi lại cho

phía client. Sự giao tiếp như vậy gọi là tin cậy bởi vì dữ liệu sẽ không bị mất mát,

sai lệch trong quá trình truyền, server gửi cho client thông điệp gì thì phía client sẽ

nhận được thông điệp nguyên như vậy. Giao thức TCP sẽ cung cấp cho chúng ta

một cách thức truyền tin cậy. Để có thể nói chuyện được trên TCP thì chương

trình client và chương trình server phải thiếp lập một đường truyền, và mỗi

chương trình sẽ phải kết nối lại với socket là điểm cuối để kết nối, client và server

muốn nói chuyện với nhau thì sẽ phải thông qua socket, mọi thông điệp sẽ phải đi

qua socket. Chúng ta cứ mường tượng socket ở đây là một cái cửa mọi người

muốn đi ra hay đi vào đều phải thông qua cái cửa này.

II. SOCKET LÀ GÌ?

Một socket là một điểm cuối của thông tin hai chiều liên kết giữa hai chương

trình đang chạy trên mạng. Những lớp socket được dùng để đại diện cho kết nối

giữa một chương trình client và một chương trình server. Trong Java gói Java.net

cung cấp hai lớp Socket và ServerSocket để thực hiện kết nối giữa client và server.

Thông thường thì server sẽ chạy trên một máy đặc biệt và có một socket giới

hạn trong một Port number đặc biệt.

Phía client: client được biết hostname của máy mà server đang chạy và port

number mà server đang lắng nghe. Để tạo một yêu cầu kết nối client sẽ thử hẹn

gặp server ở trên máy của server thông qua port number. Client cũng cần xác

định chính nó với server thông qua local port number.

Nếu mọi thứ tốt đẹp thì server sẽ đồng ý kết nối. khi đồng ý kết nối thì server

sẽ tạo ra một socket mới để nói chuyện với client và cũng tạo ra một socket khác

để tiếp tục lắng nghe.

2

Page 3: Lap Trinh Socket Voi Java

Sau đây là hướng dẫn lập trình socket trong Java.

III. LẬP TRÌNH SOCKET BẰNG JAVA.

Cài đặt Java.

Chúng ta sẽ cài đặt một bộ JDK và một môi trường phát triển.

Để cài đặt JDK chúng ta làm như sau:

Download JDK theo địa chỉ:

https://sdlc6d.sun.com/ECom/EComActionServlet/DownloadPage:~:com.sun.suni

t.sdlc.content.DownloadPageInfo;jsessionid=8768F4A376837F76F224EEF98B21

03B1;jsessionid=8768F4A376837F76F224EEF98B2103B1

Trong đó sẽ có các bản dành cho Windows và Linux.

Để cài đặt một môi trường phát triển(ở đây ta dùng Netbean)

Địa chỉ download:

https://sdlc2b.sun.com/ECom/EComActionServlet/DownloadPage:~:com.sun.suni

t.sdlc.content.DownloadPageInfo;jsessionid=FB9B3F6AB51ADD296B99E6C8A

54F69B1;jsessionid=FB9B3F6AB51ADD296B99E6C8A54F69B1

Trong đó sẽ có các bản dành cho Windows và Linux.

Các hàm thao tác trên Socket:

Đầu tiên chương trình phía server phải chạy và lắng nghe trên một cổng nào

đó để chờ phía client kết nối tới, nếu kết nối thành công thì cả hai phía đều có hai

thể hiện của lớp socket và dữ liệu sẽ được truyền qua hai lớp socket này.

Thông thường trong một chương trình sẽ có các bước cơ bản sau:

1. Mở một socket.

2. Mở một input stream và output stream tới socket.

3. Đọc và viết tới stream thông qua giao thức của server.

4. Đóng Stream.

5. Đóng socket.

3

Page 4: Lap Trinh Socket Voi Java

Phía server mở một socket bằng cách sau:

ServerSocket serverSocket = null;

try {

serverSocket = new ServerSocket(PortNumber);

} catch (IOException e) {

System.err.println("Could not listen on port: "+ PortNumber);

System.exit(1);

}

Phía server cần phải khởi tạo đối tượng của lớp ServerSocket để lắng nghe và

chấp nhận kết nối từ client. Trong đó PortNumber là số hiệu cổng server mở ra

để “lắng nghe” (chú ý: các cổng từ 0-1023 được sử dụng cho các ứng dụng đặc

biệt như: HTTP, FTP, SMTP nên chúng ta chỉ chọn các cổng từ 1024 trở đi).

Socket clientSocket = null;

try {

clientSocket = serverSocket.accept();

} catch (IOException e) {

System.err.println("Accept failed.");

System.exit(1);

}

Phía client mở socket bằng cách sau:

Socket MySocket = null;

try {

MySocket = new Socket("Machine name", PortNumber);

} catch (UnknownHostException e) {

System.err.println("Don't know about host: ");

System.exit(1);

}

4

Page 5: Lap Trinh Socket Voi Java

Trong đó Machine name là tên (hoặc địa chỉ IP) của máy tính server,

PortNumber là số hiệu cổng mà server đang lắng nghe.

Sau khi đã mở được socket để cho client và server có thể gửi và nhận thông

điệp với nhau thì chúng ta phải khởi tạo đối tượng Input Stream và Output

Stream.

Tạo đối tượng Input Stream

Phía client phải sử dụng lớp BufferedReader để tạo input với mục đích để

nhận thông điệp từ server.

BufferedReader in = null;

try {

in = new BufferedReader(new InputStreamReader(

MySocket.getInputStream()));

} catch (IOException e) {

System.err.println("Couldn't get I/O for the connection to: local

host.");

System.exit(1);

}

Phía server cũng sử dụng lớp BufferedReader để nhận thông điệp tương tự

như ở phía client.

Tạo đối tượng Output Stream.

Phía client sẽ sử dụng lớp PrintWriter để gửi thông điệp qua cho server.

PrintWriter out = null;

try {

out = new PrintWriter(MySocket.getOutputStream(), true);

} catch (IOException e) {

System.err.println("Couldn't get I/O for the connection to: local

host.");

System.exit(1);

}

5

Page 6: Lap Trinh Socket Voi Java

Bên phía server muốn gửi thông điệp cho client thì cũng làm tương tự như bên

client đã hướng dẫn ở trên.

Đóng kết nối.

Sau khi việc gửi và nhận thông điệp giữa client và server đã thực hiện xong thì

ta sẽ phải ngắt kết nối, chú ý: phải đóng input và output stream trước khi đóng

socket.

Phía client:

Try {

Out.close();

In.close();

MySocket.close();

} catch (IOException e) {

System.out.println(e);

}

Phía server:

Try {

Out.close();

In.close();

clientSocket.close();

serverSocket.close();

} catch (IOException e) {

System.out.println(e);

}

IV. Một số ví dụ:

1. ví dụ 1:

Tạo một project trong đó có 2 file là: Server.java và Client.java, đây là một ví

dụ đơn giản ban đầu để minh họa một ứng dụng server/client. Server sẽ mở cổng

1234 để cho client kết nối tới, sau khi kết nối thành công thì server sẽ gửi cho

6

Page 7: Lap Trinh Socket Voi Java

client thông điệp là: Hello World sau khi client nhận được thông điệp này thì sẽ

đóng kết nối lại.

Mã nguồn của Server.java:

import java.net.*;import java.io.*;

public class Server { public static void main(String[] args) throws IOException {

ServerSocket serverSocket = null; String data= "Hello World"; try { serverSocket = new ServerSocket(1234); System.out.println("Server listening"); } catch (IOException e) { System.err.println("Could not listen on port: 1234."); System.exit(1); }

Socket clientSocket = null; try { clientSocket = serverSocket.accept(); PrintWriter out = new

PrintWriter(clientSocket.getOutputStream(), true); out.print(data); out.close(); } catch (IOException e) { System.err.println("Accept failed."); System.exit(1); } clientSocket.close(); serverSocket.close(); }}

Đầu tiên đối tượng ServerSocket được khởi tạo để lắng nghe ở cổng 1234.

Sau khi khởi tạo thì đối tượng socket sử dụng phương thức accept() để đợi client

kết nối tới. Khi việc kết nối thành công ta sẽ tạo đối tượng output stream để gửi

7

Page 8: Lap Trinh Socket Voi Java

thông điệp cho client, thông điệp sẽ được gửi sang cho client thông qua phương

thức Print().

Đây là mã nguồn của Client.java:

import java.io.*;import java.net.*;

public class Client { public static void main(String[] args) throws IOException {

Socket MySocket = null; BufferedReader in = null;

try { MySocket = new Socket("localhost", 1234); in = new BufferedReader(new

InputStreamReader(MySocket.getInputStream())); String fromServer= in.readLine(); System.out.print(fromServer); in.close(); } catch (UnknownHostException e) { System.err.println("Don't know about host:"); System.exit(1); } catch (IOException e) { System.err.println("Couldn't get I/O for the connection to:"); System.exit(1); } MySocket.close(); }}

Một đối tượng socket được tạo ra để kết nối với server. Ở đây client sẽ kết nối

với server qua địa chỉ localhost ở cổng 1234- cổng mà server đã mở và đang lắng

nghe. Sau đó sẽ tiếp tục tạo đối tượng input stream để nhận thông điệp từ server,

khi đã nhận được thông điệp từ server thì client sẽ in thông điệp đó ra và đóng kết

nối lại.

8

Page 9: Lap Trinh Socket Voi Java

2. ví dụ 2:

Bên trên chỉ là ví dụ đơn giản để minh họa cho ứng dụng server/client. Sau

đây sẽ là một ví dụ khác trong đó server và client sẽ nói chuyện với nhau nhiều

hơn, server sẽ tạo ra một protocol để nói chuyện, client sẽ phải tuân thủ theo

protocol đó.

Tạo một project có chứa 3 file là: ChamSocServer.java, ChamSocClient.java,

ChamSocProtocol.java. Trong đó ChamSocProtocol.java sẽ quy định quy tắc nói

chuyện giữa client và server. Trong ví dụ này thì ta giải định đây là một hệ thống

trả lời chăm sóc khách hàng của một công ty nào đó. Khi kết nối thành công server

sẽ gửi lại cho client thông điệp là: “Xin chao mung cac ban den voi dich vu cham

soc khach hang!!” tức là kết nối đã thành công, khi đó client sẽ bắt đầu đưa ra các

yêu cầu để server trả lời. Ở đây quy định là client chỉ được hỏi hai câu hỏi và sau

đó phải trả lời một câu và phải theo đúng thứ tự sau: câu 1: "day la dv gi?", sau khi

được server trả lời thì client sẽ phải tiếp tục hỏi tiếp câu thứ 2 là: "la gi?" khi đó

server sẽ trả lời bạn và hỏi lại bạn một câu: “Ban co muon chuyen den dv khac?

(y/n)” nếu client trả lời “y” thì server sẽ chuyển đến dịch vụ tiếp theo và client sẽ

lại thực hiện lại quá trình như trên, còn nếu client trả lời là “n” thì quá trình nói

chuyện kết thúc và đóng kết nối lại.

Sau đây là mã nguồn chương trình:

9

Page 10: Lap Trinh Socket Voi Java

Mã nguồn file ChamSocServer.java:

import java.net.*;import java.io.*;

public class ChamSocServer { public static void main(String[] args) throws IOException {

ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(1234); System.out.println("Server listening"); } catch (IOException e) { System.err.println("Could not listen on port: 1234."); System.exit(1); }

Socket clientSocket = null; try { clientSocket = serverSocket.accept(); } catch (IOException e) { System.err.println("Accept failed."); System.exit(1); }

PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);

BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

String inputLine, outputLine; ChamSocProtocol kkp = new ChamSocProtocol();

outputLine = kkp.processInput(null); out.println(outputLine);

while ((inputLine = in.readLine()) != null) { outputLine = kkp.processInput(inputLine); out.println(outputLine); if (outputLine.equals("Bye.")) break; } out.close();

10

Page 11: Lap Trinh Socket Voi Java

in.close(); clientSocket.close(); serverSocket.close(); }}

Mã nguồn file ChamSocProtocol.java:

import java.net.*;import java.io.*;

public class ChamSocProtocol { private static final int WAITING = 0; private static final int SENT = 1; private static final int SENTCLUE = 2; private static final int ANOTHER = 3;

private static final int NUMJOKES = 5;

private int state = WAITING; private int count = 0;

private String[] clues = { "Gioi thieu", "Cac san pham", "Cac tinh nang", "Tu van", "Thong tin lien lac" }; private String[] answers = { "Se gioi thieu ve cong ty cua chung toi!", "Trung bay mot so san pham cua cong ty!", "Neu nhung tinh nang noi bat cua cac san pham!", "Chung toi se tu van cho cac ban nhung san pham phu hop voi cac ban!", "O day se la dia chi lien lac cua cong ty chung toi!" };

public String processInput(String theInput) { String theOutput = null;

if (state == WAITING) { theOutput = "Xin chao mung cac ban den voi dich vu cham soc khach hang!!"; state = SENT; } else if (state == SENT) { if (theInput.equalsIgnoreCase("day la dv gi?")) { theOutput = clues[count]; state = SENTCLUE; } else {

11

Page 12: Lap Trinh Socket Voi Java

theOutput = "Ban phai hoi la: \"day la dv gi?\"! " + "Try again.";

} } else if (state == SENTCLUE) { if (theInput.equalsIgnoreCase("la gi?")) { theOutput = answers[count] + " Ban co muon chuyen den dv khac? (y/n)"; state = ANOTHER; } else { theOutput = "Ban phai hoi la: \"la gi?\"! " +

"Try again."; state = SENTCLUE; } } else if (state == ANOTHER) { if (theInput.equalsIgnoreCase("y")) { theOutput = "Xin chao ban den voi DV tiep theo"; if (count == (NUMJOKES - 1)) count = 0; else count++; state = SENT; } else { theOutput = "Bye."; state = WAITING; } } return theOutput; }}

Đây là quy tắc nói chuyện giữa client và server như đã nói ở trên.

Mã nguồn file ChamSocClient.java:

import java.io.*;import java.net.*;

public class ChamSocClient { public static void main(String[] args) throws IOException {

12

Page 13: Lap Trinh Socket Voi Java

Socket csSocket = null; PrintWriter out = null; BufferedReader in = null;

try { csSocket = new Socket("localhost", 1234); out = new PrintWriter(csSocket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(csSocket.getInputStream())); } catch (UnknownHostException e) { System.err.println("Don't know about host: localhost."); System.exit(1); } catch (IOException e) { System.err.println("Couldn't get I/O for the connection to: localhost."); System.exit(1); }

BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); String fromServer; String fromUser;

while ((fromServer = in.readLine()) != null) { System.out.println("Server: " + fromServer); if (fromServer.equals("Bye.")) break;

fromUser = stdIn.readLine(); if (fromUser != null) { System.out.println("Client: " + fromUser); out.println(fromUser);

} }

out.close(); in.close(); stdIn.close(); csSocket.close(); }}

13

Page 14: Lap Trinh Socket Voi Java

Trên đây là một chương trình ứng dụng client/server khá điển hình, trong ví

dụ trên chỉ là một server phục vụ một client mà thôi, tuy nhiên trong thực tế lại

không phải là một server phục vụ một client nữa mà là một server phục vụ nhiều

client. Để có thể làm được điều đó thì trong Java có cơ chế đa luồng, tức là mỗi

khi có một yêu cầu kết nối từ một client nào đó thì server sẽ tạo ra một luồng để

kết nối với client đó. Như vậy thì trong cùng một lúc sẽ có thể có rất nhiều client

cùng kết nối đến một server. Sau đây sẽ là mã nguồn của chương trình:

3. Ví dụ 3:

Mã nguồn file ChamSocServer.java:

import java.net.*;import java.io.*;

public class ChamSocServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = null; boolean listening = true;

try { serverSocket = new ServerSocket(1234); System.out.println("Server is listening"); } catch (IOException e) { System.err.println("Could not listen on port: 1234."); System.exit(-1); }

while (listening) new ServerThread(serverSocket.accept()).start();

serverSocket.close(); }}

Mã nguồn file ServerThread.java:

import java.net.*;import java.io.*;

14

Page 15: Lap Trinh Socket Voi Java

public class ServerThread extends Thread { private Socket socket = null;

public ServerThread(Socket socket) {super("ServerThread");this.socket = socket;

}

public void run() {

try { PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(

new InputStreamReader( socket.getInputStream()));

String inputLine, outputLine; Protocol cs = new Protocol(); outputLine = cs.processInput(null); out.println(outputLine);

while ((inputLine = in.readLine()) != null) {outputLine = cs.processInput(inputLine);out.println(outputLine);if (outputLine.equals("Bye")) break;

} out.close(); in.close(); socket.close();

} catch (IOException e) { e.printStackTrace();}

}}

Mã nguồn file Protocol.java:

import java.net.*;import java.io.*;

15

Page 16: Lap Trinh Socket Voi Java

public class Protocol { private static final int WAITING = 0; private static final int SENT = 1; private static final int SENTCLUE = 2; private static final int ANOTHER = 3;

private static final int NUMJOKES = 5;

private int state = WAITING; private int count = 0;

private String[] clues = { "Gioi thieu", "Cac san pham", "Cac tinh nang", "Tu van", "Thong tin lien lac" }; private String[] answers = { "Se gioi thieu ve cong ty cua chung toi!", "Trung bay mot so san pham cua cong ty!", "Neu nhung tinh nang noi bat cua cac san pham!", "Chung toi se tu van cho cac ban nhung san pham phu hop voi cac ban!", "O day se la dia chi lien lac cua cong ty chung toi!" };

public String processInput(String theInput) { String theOutput = null;

if (state == WAITING) { theOutput = "Xin chao mung cac ban den voi dich vu cham soc khach hang!!"; state = SENT; } else if (state == SENT) { if (theInput.equalsIgnoreCase("day la dv gi?")) { theOutput = clues[count]; state = SENTCLUE; } else { theOutput = "Ban phai hoi la: \"day la dv gi?\"! " +

"Try again."; } } else if (state == SENTCLUE) { if (theInput.equalsIgnoreCase("la gi?")) { theOutput = answers[count] + " Ban co muon chuyen den dv khac? (y/n)"; state = ANOTHER; } else { theOutput = "Ban phai hoi la: \"la gi?\"! " +

16

Page 17: Lap Trinh Socket Voi Java

"Try again."; state = SENTCLUE; } } else if (state == ANOTHER) { if (theInput.equalsIgnoreCase("y")) { theOutput = "Xin chao ban den voi DV tiep theo"; if (count == (NUMJOKES - 1)) count = 0; else count++; state = SENT; } else { theOutput = "Bye."; state = WAITING; } } return theOutput; }}

Mã nguồn file ChamSocClient.java:

import java.io.*;import java.net.*;

public class ChamSocClient { public static void main(String[] args) throws IOException {

Socket csSocket = null; PrintWriter out = null; BufferedReader in = null;

try { csSocket = new Socket("localhost", 1234); out = new PrintWriter(csSocket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(csSocket.getInputStream())); } catch (UnknownHostException e) { System.err.println("Don't know about host: localhost."); System.exit(1); } catch (IOException e) { System.err.println("Couldn't get I/O for the connection to: localhost.");

17

Page 18: Lap Trinh Socket Voi Java

System.exit(1); }

BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); String fromServer; String fromUser;

while ((fromServer = in.readLine()) != null) { System.out.println("Server: " + fromServer); if (fromServer.equals("Bye.")) break;

fromUser = stdIn.readLine(); if (fromUser != null) { System.out.println("Client: " + fromUser); out.println(fromUser);

} }

out.close(); in.close(); stdIn.close(); csSocket.close(); }}

Hy vọng đọc đến đây mọi người có thể hiểu một phần nào đó về Socket, và có

thể tự viết được một số ứng dụng client-server.

Good Luck!

18