Cờ caro là một trò chơi nhỏ hấp dẫn và không thiếu phần sáng tạo, chắc hẳn ai cũng từng trải nghiệm qua trò chơi nhỏ này trong những lúc xả stresscùng bạn bè. Nhưng trong cuộc sống hiện đại ngày nay chúng ta không thể trực tiếp ngồi chơi cờ cùng nhau. Vì thế, chơi cờ caro online qua mạng đã ra đời phục vụ nhu cầu đó.
16 trang |
Chia sẻ: vietpd | Lượt xem: 1355 | Lượt tải: 1
Bạn đang xem nội dung tài liệu Luận văn Lập trình phân tán trên Java, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
GIỚI THIỆU
1. Lý do chọn đề tài
Cờ caro là một trò chơi nhỏ hấp dẫn và không thiếu phần sáng tạo, chắc
hẳn ai cũng từng trải nghiệm qua trò chơi nhỏ này trong những lúc xả stress
cùng bạn bè. Nhưng trong cuộc sống hiện đại ngày nay chúng ta không thể trực
tiếp ngồi chơi cờ cùng nhau. Vì thế, chơi cờ caro online qua mạng đã ra đời
phục vụ nhu cầu đó.
2. Yêu cầu
2.1. Server:
• Lắng nghe.
• Phục vụ yêu cầu của Client.
• Xử lý nước đi của các Client để gửi kết quả thắng thua trong bàn cờ
cho các Client trong bàn cờ.
2.2. Client:
• Kết nối Server.
• Gửi yêu cầu cho Server phục vụ: mời chơi, chấp nhận lời mời, nước
đi, chơi lại.
3. Một số kỹ thuật liên quan
• Sử dụng mô hình mạng Client/Server, giao thức TCP/IP.
• Cổng kết nối 9000.
• Sử dụng Socket và kỹ thuật multithread trong Java, và một số tính
năng khác.
• Lựa chọn ngôn ngữ: Java. (Java được xem là một ngôn ngữ lập trình
ứng dụng cho mạng vì những đặc tính riêng biệt của chúng như đa hệ nền,
đa luồng, bảo mật, hướng đối tượng, phân tán, ứng dụng web…).
4. Nội dung
4.1. Server
4.1.1. Giao diện Server có các chức năng sau:
Start Server.
Listbox danh sách những người đang online.
Listbox cập nhật các player đang chơi.
Text Area lưu thông tin kết nối đến Server của các player.
4.1.2. Các giao thức liên lạc giữa Server và Client
Connect: liên lạc connect giữa client và server. Khi client đăng
nhập thì nó sẽ gửi một chuỗi: “Connect:username”.
Cổng mặc định nhận giao thức giữa Server và Client là cổng 9000.
Disconnect : client gửi tín hiệu ngắt kết nối, Server gửi đi tính
hiệu khi có client ngắt kết nối cho toàn thể client:
“Disconnect:username”.
CallPlay: client gửi tính hiệu mời một client khác chơi cờ:
“CallPlay:username_của_người_mời:username_của_đối_thủ”.
Yes: client( đối thủ) đồng ý chơi, client gửi lên:
“Yes:username_người_yes:username_người mời mình”.
KieuConDi: khi nhận được tín hiệu đồng ý chời, server gửi kiểu
con đi quy định cho trước (X or O).
“KieuConDi:username1:X:username2:O” (username1 đi X,
username2 đi O).
Play: client gửi nước đi của mình lên server:
“Play:username_của_mình::
username_của_đối_thủ”.
Played: server nhận được tín hiệu client gửi nước đi, server gửi về
client trở lại: “Played:username1::username2”.
RePlay: client gửi tín hiệu chơi lại lên server cho đối thủ kia biết
là mình muốn chơi lại:
“RePlay:username_của_mình:username_đối_thủ”.
WIN: server gửi tín hiệu người thắng cuộc.
“WIN:username_thăng::username_thua”.
Lose: xử thua cho một client nào đó: “Lose:username”.
ReConnect: client gửi tín hiệu connect lại để chơi với người khác,
khi không muốn chơi với người A nữa:
“ReConnect:username_của_mình”.
4.1.3. Class chính trong chương trình phía Server: Server.java
a. RefreshListUserPlaying
Cập nhật danh sách những người đang chơi game.
while(userPlaying != null){
String display = "";
for(String s:userPlaying){
if(display.equals("")){
display = s;
}
else{
display = display + ":" + s;
}
}
String []sql = display.split(":");
jListPlaying.setListData(sql);
}
b. refreshListUser
Cập nhật danh sách những người đang online.
while(userOnline != null){
String display = "";
for(String s:userOnline){
if(display.equals("")){
display = s;
}
else{
display = display + ":" + s;
}
}
String []sql = display.split(":");
jListConnected.setListData(sql);
}
c. processRequest
Tạo kết nối Client với Server thông qua lớp Connection.java
try{
communitySocket = serverSocket.accept();
handleConnection(communitySocket);
System.out.println("So luong ket noi: " +
listCon.size() + "\n" + "so luong
user online: " + userOnline.size());
}catch(Exception e){
e.printStackTrace();
}
d.Các Function chính
addUser(String UserID, Connection con): thêm một user mới
vào list user online tương ứng với một connection.
addUserFree(String uid): thêm một user chưa chọn được bạn
chơi game.
addUserPlay(String userid) : thêm một user vào danh sách
những người đã có bạn chơi (đang chơi).
closeConnection(Connection con, String uid): đóng kết nối
tương ứng với user đã đăng ký (khi nhận tín hiệu disconnect từ
client gửi về).
listCon.remove(con);
userOnline.remove(uid);
userIDToConnect.remove(uid);
if(userPlaying != null && userPlaying.size() > 0 &&
userPlaying.contains(uid))
userPlaying.remove(uid);
if(userFree != null && userFree.size() > 0 &&
userFree.contains(uid))
userFree.remove(uid);
removeUserPlay(String user): xóa những user đã chọn được
bạn chơi trong danh sách người chời chưa chọn được bạn chơi.
runServer() : chạy luồng chính của server (lắng nghe-chờ tín
hiệu kết nối từ client).
userOnline = new ArrayList();
userPlaying = new ArrayList();
userFree = new ArrayList();
listCon = new ArrayList();
userIDToConnect = new HashMap<String,
Connection>();
Thread serverThread = new Thread(new
processRequest());
serverThread.start();
Thread refresh = new Thread(new
refreshListUser());
refresh.start();
Thread playing = new Thread(new
RefreshListUserPlaying());
playing.start();
sendToAllClient(string): gửi tín hiệu phản hồi từ server đến tất
cả các client.
setDetailConnect(string): server lưu vết các client connect &
disconnect.
handleConnect(Socket clientSocket): tạo một Connection cho
một socket client.
Connection conn = new Connection(this,
clientSocket);
Thread t = new Thread(conn);
t.start();
listCon.add(conn);
Các class còn lại dùng để mở rộng ứng dụng sau này.
4.1.4. Class hổ trợ: Connection.java
a. CreateBanco: Tạo bàn cờ, set kiểu con đi cho các player, phân tích
nước đi để đưa ra quyết định thắng thua.
b. Player: Tạo người chơi.
protected String player = null;
protected String kieudi = null;
protected String status = "NONE";
public Player(String p, String k){
player = p;
kieudi = k;
status = "NONE";
}
public void setstatus(String t){
status = t;
}
public String getPlayer(){
return player;
}
public String getKieuDi(){
return kieudi;
}
c. Các Function:
Connection(Server ser, Socket s): Định nghĩa các biến.
public Connection(Server ser, Socket s){
server = ser;
communitySocket = s;
}
closeConnectionSocket(): Đóng kết nối các Client đã
closeconnection.
try{
if(in != null) in.close();
if(out != null) out.close();
communitySocket.close();
player1 = null;
player2 = null;
userID1 = null;
userID2 = null;
}catch(Exception ex){
}
run(): Lắng nghe các kết nối, yêu cầu từ phía Client, thực thi,
kiểm tra yêu cầu và trả về kết quả phù hợp với các yêu cầu của
Client.
OutputStream socketOut = null;
InputStream socketIn = null;
while(true){
try{
if(communitySocket.isClosed())
break;
socketOut = communitySocket.getOutputStream();
out = new OutputStreamWriter(socketOut);
socketIn = communitySocket.getInputStream();
if(socketIn == null)
return;
in = new BufferedReader(new InputStreamReader(socketIn));
String input = in.readLine();
System.out.println(input);
System.out.println( "Nhan cho nay 2.");
if(input.equals("") || input.isEmpty() || input.toString()
== null){
System.out.println("Null rui?");
return;
}
header:userID1:port:hostAddress:userID2:port:hostAddress
neu la callPlay
if(input.startsWith("Connect:")){
String detail[] =
input.substring(8).split(":");
if(detail.length > 0){
userID = detail[0];
System.out.println(userID);
listenPortofClient =
communitySocket.getPort();
hostAdress =
communitySocket.getInetAddress().toString();
this.server.addUser(userID, this);
this.server.setDetailConnection(userID + "
connect from " + communitySocket.getInetAddress() + "
from port: " + communitySocket.getPort());
}
}
else if(input.startsWith("ReConnect:")){
String detail[] =
input.substring(10).split(":");
if(detail.length > 0){
this.server.addUserFree(detail[0])
;
this.server.removeUserPlay(detail[
0]);
bc = null;
}
}
else if(input.startsWith("Disconnect:")){
String detail[] =
input.substring(11).split(":");
this.server.closeConnection(this,
detail[0]);
this.server.setDetailConnection(userID + "
disconnected");
this.server.sendToAllClient("Disconnec
t:" + userID);
closeConnectionSocket();
}
else if(input.startsWith("CallPlay:")){
String detail[] =
input.substring(9).split(":");
if(detail.length > 0){
this.server.sendToAllClient("CallPlay:" +
detail[1] + ":" + detail[0]);
}
}
else if(input.startsWith("NoRePlay:")){
String detail[] =
input.substring(9).split(":");
if(detail.length > 0){
this.server.removeUserPlay(detail[0]);
this.server.addUserFree(detail[0])
;
this.server.sendToAllClient("NoRePlay:" + detail[0]);
}
}
…
}
4.2. Client
4.2.1. Giao diện chính Client
Địa chỉ IP của Server
Tên của bạn
Danh sách người đang online: danh sách những người chưa chơi
Button “Mời chơi”: khi chọn người muốn chơi xong thì click vào
nút mời chơi, người được mời chơi sẽ xuất hiện hộp thông báo:
Nếu đồng ý chơi thì click vào “yes”.
Giao diện bàn cờ sẽ xuất hiện như sau:
4.2.2. Class chính chương trình Client BanCoJFrame.java
a. Vòng lập “for” tạo bàn cờ
jPanelBanCo.setLayout(new GridLayout(10, 10));
for(int i = 0; i < 10; ++i)
for(int j = 0; j < 10; ++j){
btn[i][j] = new Button("");
btn[i][j].setSize(35, 35);
btn[i][j].setActionCommand("bt" + i + "_" + j);
btn[i][j].setCursor(new
java.awt.Cursor(java.awt.Cursor.CROSSHAIR_CURSOR));
btn[i][j].setFont(new Font("Times New Roman",
1, 16));
btn[i][j].addActionListener(new
ActionListener(){
public void actionPerformed(ActionEvent e)
{
choice = e.getActionCommand();
send();
disable();
}
});
jPanelBanCo.add(btn[i][j]);
}
b. class ClassReceive
Nhận các giao thức từ Server để xử lý
public void run(){
try{
while(true){
in = new BufferedReader(new
InpuStreamReader(socket.getInputStream()));
out = new
PrintWriter(socket.getOutputStream());
String input = in.readLine();
if(input == null){
System.out.println("du lieu bi null");
return;
}
System.out.println(input);
String []detail = input.split(":");
int n = detail.length;
System.out.println(n);
if(n > 0){
if(detail[0].equals("Update")){
String []spl = new String[n-1];
int j = 0;
for(int i = 1; i < n; ++i){
System.out.println(detail[i]);
if(!detail[i].equals("") && !
detail[i].equals(jTextFieldDangNhap.getText()))
spl[j++] = detail[i];
}
jListDanhSach.setListData(spl);
}
else if(detail[0].equals("Disconnect")){
if(detail[1].equals(usernameCalled)){
String message = "Đối phương đã nghỉ
chơi!\nBạn có muốn chơi nữa không?\nClick Yes để tìm
người chơi khác.\nClick No để thoát khỏi trò chơi.";
int answer =
JOptionPane.showConfirmDialog(frame, message, "Thông
báo", JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
if(answer == JOptionPane.YES_OPTION){
jButtonMoiChoi.setEnabled(true);
out.println("ReConnect:" + username);
out.flush();
clearBanCo();
jPanelBanCo.setVisible(false);
}
else if(answer == JOptionPane.NO_OPTION)
{
out.println("Disconnect:" + username);
out.flush();
setVisible(false);
dispose();
}
}
}
else if(detail[0].equals("CallPlay")){
if(detail[1].equals(username)){
int resulf =
JOptionPane.showConfirmDialog(frame, "Bạn nhận được lời
mời từ " + username, "Mời chơi",
JOptionPane.YES_NO_OPTION);
if(resulf == JOptionPane.YES_OPTION){
out.println("Yes:" + username + ":" +
detail[2]);
jPanelBanCo.setVisible(true);
jButtonMoiChoi.setEnabled(false);
if(detail[2] != null && !
detail[2].equals(username))
usernameCalled = detail[2];
LabelPlayer2.setText(usernameCalled);
}
else{
out.println("No:" + username + ":" +
detail[2]);
jPanelBanCo.setVisible(false);
jButtonMoiChoi.setEnabled(true);
usernameCalled = null;
}
out.flush();
}
}
else if(detail[0].equals("Yes")){
if(detail[2].equals(username)){
jPanelBanCo.setVisible(true);
jButtonMoiChoi.setEnabled(false);
usernameCalled = detail[1];
jLabelPlayer1.setText(username);
jLabelPlayer2.setText(usernameCalled);
jLabelKq.setText("Ai thắng đây ta ???");
jLabelDiTruoc.setText(goFirst);
}
else if(detail[1].equals(username)){
jPanelBanCo.setVisible(true);
jButtonMoiChoi.setEnabled(false);
usernameCalled = detail[2];
jLabelPlayer1.setText(username);
jLabelPlayer2.setText(usernameCalled);
jLabelKq.setText("Ai thắng đây ta ???");
jLabelDiTruoc.setText(goFirst);
}
}
else if(detail[0].equals("No")){
if(detail[1].equals(username) &&
detail[2].equals(usernameCalled)){
jPanelBanCo.setVisible(false);
jButtonMoiChoi.setEnabled(true);
}
jLabelDiTruoc.setText(" ");
}
else if(detail[0].equals("KieuConDi")){
if(detail[1].equals(username)){
if(detail[4] != null)
kieucondi = detail[2];
if(detail[4] != null)
kieuConDiDoiThu = detail[4];
}
else if(detail[3].equals(username)){
if(detail[4] != null)
kieucondi = detail[4];
if(detail[2] != null)
kieuConDiDoiThu = detail[2];
}
}
else if(detail[0].equals("Played")){
if(detail[1].equals(usernameCalled)){
if(detail[3] != null){
String nuocdi[] = detail[2].split(",");
if(nuocdi.length > 1){
setNuocDi(Integer.parseInt(nuocdi[0]),
Integer.parseInt(nuocdi[1]), kieuConDiDoiThu);
ToDo(10);
}
}
}
else if(detail[1].equals(username)){
}
}
else if(detail[0].equals("WIN")){
if(detail[2] != null){
String nuocdi[] = detail[2].split(",");
if(nuocdi.length > 1)
setNuocDi(Integer.parseInt(nuocdi[0]),
Integer.parseInt(nuocdi[1]), kieuConDiDoiThu);
}
if(detail[1].equals(username)){
jLabelKq.setText("Bạn đã thắng!");
clearBanCo();
jPanelBanCo.setVisible(false);
}
else if(detail[3] != null &&
detail[3].equals(username)){
System.out.println(detail[3] + "=" +
usernameCalled);
jLabelKq.setText("Bạn đã thua rồi!");
waiting(5);
String message = "Bạn đã thua rồi! Bạn có muốn
chơi nữa không?\n Click Yes để chơi lại.\n Click No để
tìm người chơi khác.";
int answer =
JOptionPane.showConfirmDialog(frame, message, "Thông
báo", JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
if(answer == JOptionPane.YES_OPTION){
jButtonMoiChoi.setEnabled(true);
out.println("CallPlay:" + usernameCalled +
":" + username);
out.flush();
clearBanCo();
timeWaiting.cancel();
}
else if(answer == JOptionPane.NO_OPTION){
out.println("ReConnect:" + username);
out.flush();
clearBanCo();
jPanelBanCo.setVisible(false);
out.println("NoRePlay:" + usernameCalled);
out.flush();
jButtonMoiChoi.setEnabled(true);
timeWaiting.cancel();
}
}
}
else if(detail[0].equals("NoRePlay")){
if(detail[1] != null &&
detail[1].equals(usernameCalled)){
jButtonMoiChoi.setEnabled(true);
}
}
}
}
}catch(Exception ex){
System.out.println("Khong the nhan du lieu.");
ex.printStackTrace();
}
}
c. Các function chính
Function doConnected(): quản lí việc đăng nhập của user
public boolean doConnected(){
try{
if(jTextFieldDangNhap.getText().length() <= 30){
String ip = jTextFieldIP.getText();
socket = new Socket(ip, 9000);
jLabelPlayer1.setText(jTextFieldDangNhap.getText());
out = new PrintWriter(socket.getOutputStream());
out.println("Connect:" + jTextFieldDangNhap.getText());
out.flush();
username = jTextFieldDangNhap.getText();
ClassReceive r = new ClassReceive();
read = new Thread(r);
read.start();
jButtonDangNhap.setEnabled(false);
jButtonMoiChoi.setEnabled(true);
return true;
}
else{
JOptionPane.showMessageDialog(frame, "Tên bạn quá 30
kí tự, vui lòng đăng nhập lai!");
jButtonDangNhap.setEnabled(true);
}
}catch(Exception e){
JOptionPane.showMessageDialog(frame, "Kết nối không
thành công vui lòng đăng nhập lại!");
jButtonDangNhap.setEnabled(true);
}
return false;
}
Function send(): thực hiện gửi nước đi, kiểu con đi.
public void send(){
try {
in = new BufferedReader(new
InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream());
if(choice.equals("")){
System.out.print("Choice rong.");
return;
}
String []n1 = choice.substring(2).split("_");
if(n1.length > 0){
int i = Integer.parseInt(n1[0]);
int j = Integer.parseInt(n1[1]);
System.out.println(i);
System.out.println(j);
if(kieucondi == null && kieuConDiDoiThu != null){
if(kieuConDiDoiThu.equals("X"))
kieucondi = "O";
else if(kieuConDiDoiThu.equals("O"))
kieucondi = "X";
}
if(kieuConDiDoiThu == null && kieucondi != null){
if(kieucondi.equals("X"))
kieuConDiDoiThu = "O";
else if(kieucondi.equals("O)"))
kieucondi = "X";
}
if(kieucondi == null && kieuConDiDoiThu == null){
kieucondi = "X";
kieuConDiDoiThu = "O";
}
btn[i][j].setLabel(kieucondi);
System.out.println(username + " di kieu: " +
kieucondi);
btn[i][j].setEnabled(false);
if(time != null){
time.cancel();
time = null;
}
if(timeWaiting != null){
timeWaiting.cancel();
timeWaiting = null;
}
try{
out.println("Play:" + username + ":" + n1[0] +
"," + n1[1] + ":" + usernameCalled);
out.flush();
}catch(Exception e){
System.err.println(e);
}
}
}catch (IOException ex)
{ Logger.getLogger(BanCoJFrame.class.getName()).
log(Level.SEVERE, null, ex);
}
}
Function doReceive(Socket s): danh sách user đang online
public void doReceive(Socket s){
Socket soc = s;
try{
in = new BufferedReader(new
InputStreamReader(soc.getInputStream()));
String input = in.readLine();
if(input == null){
System.out.println("du lieu bi null");
return;
}
String []detail = input.split(":");
int n = detail.length;
if(n > 0){
if(detail[0].equals("Update")){
String []spl = new String[n-1];
for(int i = 1; i< n; ++i)
spl[i] = detail[i];
jListDanhSach.setListData(spl);
}
}
}catch(Exception ex){…}
Function callPlay(String userID): mời bạn chơi cờ
public void callPlay(String userID){
try {
out = new PrintWriter(socket.getOutputStream());
out.println("CallPlay:" + username + ":" + userID);
out.flush();
jButtonMoiChoi.setEnabled(false);
usernameCalled = userID;
} catch (IOException ex) { … }
}
Function setNuocDi(int row, int col, String kieu)
Function clearBanCo()
5. Kết quả đạt được và mặt hạn chế