网络模块
定义Message 类
在我们开发联机五子棋的过程中最大的一个问题是,各种消息太过复杂,对话消息,下棋消息,邀请消息,悔棋消息,将这些消息标准化定义,让服务器能够识别收到的到底是什么消息就很重要。因此我们专门将定义的Code类,定义了一系列内部编码,当然大家直接用宏定义也可以。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| import java.io.Serializable; import java.util.LinkedList;
public class Message implements Serializable { private static final long serialVersionUID = 1L; public String username; public String content; public String time; public String code; public boolean color; public int x,y; public int ID; public LinkedList<user> userlist; public Message(String code,int ID,String username) { this.code=code; this.ID=ID; this.username=username;
} public Message(String code,int ID) { this.code=code; this.ID=ID;
} public Message(String code, LinkedList<user> userlist) { this.code=code; this.userlist=userlist; } public Message(String code,String username,String content,String time){ super(); this.code=code; this.username=username; this.content=content; this.time=time; } public Message(String code,int x,int y,boolean color){ super(); this.code=code; this.x=x; this.y=y; this.color=color; } public Message(String code,String username) { this.code=code; this.username=username; } public Message(String code) { this.code=code;
} public Message() { super(); }
}
class Code{ public static final String MESSAGE="message"; public static final String CHESS="chess";
public static final String REQUEST="request"; public static final String BACK="back"; public static final String LOST="lost"; public static final String PEACE="peace";
public static final String LOADING="loading";
public static final String RENAME="rename";
public static final String GETID="getid";
public static final String REFUSE="refuse"; public static final String STARTGAME="startgame";
public static final String PEACEGAME="peacegame";
public static final String WINGAME="wingane";
public static final String REFUSEPEACE="refusepeace";
public static final String UPDATE="update";
public static final String OUTOFDATE="outofdate";
}
|
服务端
服务端和客户端的实例和之前的多人群聊系统相差不大,因为咱们的五子棋要设置联机大厅,所以还要储存所有用户的信息,因此服务端的程序也需要储存数据库,ServerModel类读者可以根据自己的需求创建。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| package gobang;
import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.LinkedList;
public class Server { public static ServerModel model=new ServerModel(); public static LinkedList<ObjectOutputStream>online=new LinkedList<ObjectOutputStream>(); public Server(){} public static void main(String[] arg) throws IOException {
ServerSocket ss = new ServerSocket(8000); int num = 1; int ID=0; System.out.println("正在连接中……");
while (true) { Socket s = ss.accept(); ServerThread newServerThtear=new ServerThread(s,ID); newServerThtear.start(); user newuser=new user("新用户"+ID,ID); model.adduser(newuser); System.out.println("新用户加入,当前在线用户"+num+"人");
num++; ID++; }
}
}
|
服务端线程(其实大家的服务端也可以设计一个服务端的消息管理器,但是我这里就不做演示啦,就把那一大串if-else接到一个函数里就OK)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| class ServerThread extends Thread{
private Socket s;
private ObjectInputStream ois; private ObjectOutputStream oos;
private int enemyID=-1; private int ID; public ServerThread(Socket s,int ID){ super(); this.s=s; this.ID=ID;
} public void run(){
try {
ois = new ObjectInputStream(s.getInputStream()); oos = new ObjectOutputStream(s.getOutputStream()); Server.online.addLast(oos); Message Mmsg=new Message(Code.GETID,ID,Server.model.getdata().get(ID).username); oos.writeObject(Mmsg);
while(true) { Message msg=(Message)ois.readObject(); if(msg.code.equals("message")) { if (enemyID != -1) { System.out.println(msg.time + "\n" + msg.username + ":" + msg.content); Server.online.get(enemyID).writeObject(msg); } } else if(msg.code.equals("chess")) { if (enemyID != -1) {
System.out.println(msg.time + "\n" + msg.username + ":" + msg.content); Server.online.get(enemyID).writeObject(msg); } } else if(msg.code.equals(Code.LOADING)) { Message answermsg=new Message(Code.LOADING,Server.model.getdata()); oos.writeObject(answermsg); System.out.println(Server.model.getdata().getFirst().username); } else if (msg.code.equals(Code.UPDATE)) { LinkedList<user> List=new LinkedList<>(); for(int i=0;i<Server.model.getdata().size();i++) { List.addLast(Server.model.getdata().get(i)); }
Message answermsg=new Message(Code.UPDATE,List); System.out.println(answermsg.userlist.size()); System.out.println(answermsg.userlist.getFirst().username+" "+answermsg.userlist.getLast().username); oos.writeObject(answermsg);
} else if(msg.code.equals(Code.RENAME)) { Server.model.rename(this.ID,msg.username); System.out.println("更改名字成功");
} else if(msg.code.equals(Code.REQUEST)) { Message requestmsg=new Message(Code.REQUEST,ID, msg.username); Server.online.get(msg.ID).writeObject(requestmsg); System.out.println("请求发送给"+msg.ID); this.enemyID=msg.ID;
}else if(msg.code.equals(Code.STARTGAME)) { Server.online.get(msg.ID).writeObject(msg); enemyID= msg.ID;
}else if(msg.code.equals(Code.REFUSE)) { Server.online.get(msg.ID).writeObject(msg); } else { if (enemyID != -1) { Server.online.get(enemyID).writeObject(msg); } }
} } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { throw new RuntimeException(e); }
} }
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| package gobang;
import java.io.*; import java.net.Socket; import java.net.UnknownHostException;
public class NET {
public Socket s;
public String host="localhost"; public int port=8080;
NET() {
try { s = new Socket("localhost", 8080); ObjectOutputStream os=new ObjectOutputStream(s.getOutputStream()); ObjectInputStream is=new ObjectInputStream(s.getInputStream()); SendThread sendThread=new SendThread(os); ReceiveThread receiveThread=new ReceiveThread(is); sendThread.start(); receiveThread.start();
}catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
public void SETNET() { try { s.close(); s = new Socket(host,port); ObjectOutputStream os=new ObjectOutputStream(s.getOutputStream()); ObjectInputStream is=new ObjectInputStream(s.getInputStream()); SendThread sendThread=new SendThread(os); ReceiveThread receiveThread=new ReceiveThread(is); sendThread.start(); receiveThread.start();
}catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
}
}
|
客户端发送线程
客户端的发送线程主要的工作就是检测客户端的MessageList,消息队列中是否有待处理的消息(是否为空),一旦有就立刻发送给服务端。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| package gobang;
import java.io.IOException; import java.io.ObjectOutputStream;
public class SendThread extends Thread { private ObjectOutputStream os;
public SendThread(ObjectOutputStream os) { super(); this.os = os;
}
public void run() {
try {
while (true) { System.out.print(""); if (!Vars.model.messageModel.isEmpty()) {
Message msg = Vars.model.messageModel.getFirst(); System.out.println(msg.time+"\n"+msg.username+":"+msg.content); os.writeObject(msg); Vars.model.messageModel.removeFirst();
} } } catch (IOException e) { throw new RuntimeException(e);
} }
}
|
客户端接收线程
接受线程同样只做一件事情,就是接受消息,一旦接收到消息就把它丢给消息管理器处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package gobang;
import javax.swing.*; import java.awt.*; import java.io.IOException; import java.io.ObjectInputStream;
public class ReceiveThread extends Thread{
private ObjectInputStream ois; private volatile boolean flag = true;
public ReceiveThread(ObjectInputStream ois) { super(); this.ois = ois; } public void run() {
while(true) {
System.out.print(""); Message msg = null; try { msg = (Message) ois.readObject(); Vars.messageManager.getMessage(msg); } catch (IOException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); }
}
} }
|
消息管理器
客户端咱们刚才接收到消息后,没有做任何处理,只是调用了一个messageManager里的getMessage()函数,就是丢给,消息管理器,消息管理器就是处理我们接收到的网络消息的,根据接受到1消息完成我们的对应操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| package gobang;
import javax.swing.*; import java.awt.*;
public class messageManager { public void getMessage(Message msg) { if(msg.code.equals("message")) { System.out.println(msg.time + "\n" + msg.username + ":" + msg.content); Vars.talkPanel.showarea.append(msg.time + "\n" + msg.username + ":" + msg.content + "\n"); } else if(msg.code.equals("chess")){ System.out.println(); Vars.controler.addNetChess(msg.x, msg.y); } else if(msg.code.equals(Code.BACK)){ Vars.controler.NETback(); } else if (msg.code.equals(Code.LOST)) { Vars.dialogStyle.Gameover(Start.getStart(),"对方认输");
} else if (msg.code.equals(Code.PEACE)) { Vars.dialogStyle.AnswerPeace(Start.getStart()); } else if(msg.code.equals(Code.LOADING)){ Vars.model.userList=msg.userlist; System.out.println(); } else if (msg.code.equals(Code.REQUEST)) { Vars.dialogStyle.AnswerRequest(MainWindows.getMainWindows(), msg.username, 30); Vars.model.enemyID= msg.ID; Vars.model.enemyname=msg.username; } else if (msg.code.equals(Code.REFUSE)) { Vars.dialogStyle.waitDialog(MainWindows.getMainWindows(),"对方拒绝了你的邀请",30); Vars.model.enemyID=-1; }else if(msg.code.equals(Code.STARTGAME)){ Vars.controler.turnyou=false; Vars.roundPanel.update(); Start start=Start.getStart(); Vars.timePanel.restart(); }else if(msg.code.equals(Code.PEACEGAME)){ Vars.dialogStyle.Gameover(Start.getStart(),"平局"); }else if(msg.code.equals(Code.REFUSEPEACE)){ Vars.dialogStyle.waitDialog(Start.getStart(),"对方拒绝了你的求和",10); }else if(msg.code.equals(Code.UPDATE)){
System.out.println(msg.userlist.getFirst().username+" "+msg.userlist.getLast().username); System.out.println(msg.userlist.size()); MainWindows.getMainWindows().Player.removeAll();
Vars.model.userList=msg.userlist;
if(Vars.model.userList.size()==1) {
JLabel label=new JLabel("当前无其他用户"); Font font=new Font("黑体",Font.PLAIN,50); label.setFont(font); label.setForeground(Color.decode("#0fa99a")); MainWindows.getMainWindows().Player.add(label); } else { for (int i = 0; i < Vars.model.userList.size(); i++) { if(i!=Vars.model.ID) { PlayerLabel player = new PlayerLabel(msg.userlist.get(i).username, msg.userlist.get(i).userID); MainWindows.getMainWindows().Player.add(player); }
} } JLabel label2=new JLabel("当前在线人数"+String.valueOf(msg.userlist.size())); Font font=new Font("黑体",Font.PLAIN,50); label2.setFont(font); label2.setForeground(Color.decode("#0fa99a")); MainWindows.getMainWindows().Player.add(label2); MainWindows.getMainWindows().Player.updateUI(); } else if (msg.code.equals(Code.GETID)) { System.out.println("用户信息加载成功"); System.out.println(msg.ID+msg.username); Vars.model.ID=msg.ID; Vars.model.username= msg.username;
} } }
|
这样我们的联机五子棋的主体内容就做完了!,剩下就是一些UI界面的布置和UI控件的封装和调用了,希望大家都能做出自己的五子棋。
项目已上传至github https://github.com/DemonWhiteY/Gobang_online
百度网盘 链接:https://pan.baidu.com/s/1c7dflsJ9Q-Scg-0DVgOdkg?pwd=YYDS
提取码:YYDS
–来自百度网盘超级会员V3的分享