lap trinh socket voi java
TRANSCRIPT
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
"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
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