长沙理工大学网络系统课程设计Word格式.docx
《长沙理工大学网络系统课程设计Word格式.docx》由会员分享,可在线阅读,更多相关《长沙理工大学网络系统课程设计Word格式.docx(28页珍藏版)》请在冰豆网上搜索。
对于五子棋与围棋的关系有两种说法,一说早于围棋,早在“尧造围棋”之前,民间就已有五子棋游戏;
一说源于围棋,是围棋发展的一个分支。
在中国的文化里,倍受人们的青睐。
古代的五子棋的棋具与围棋相同,纵横各十七道。
五子棋大约随围棋一起在我国南北朝时先后传入朝鲜、日本等地。
Java是一种应用于分布式网络环境中的程序设计语言,由Sun微系统公司开发。
Java语言广为人知,得益于Internet的迅猛发展。
特别是Applet在Web上的应用吸引了更多人们对Java语言的关注,人们开始了解并使用这种神奇的语言。
1.1课程设计预期
(1)实现服务器端以及客户端的功能。
(2)游戏界面朴素美观。
(3)棋子样式采用传统样式,黑色和白色。
(4)客户端的信息交流完全通过服务器传递完成。
1.2课程设计内容
本次课程设计主要分为客户机和服务器两部分的设计,其中在服务器端可以创建待机室供其它未处于下棋状态的人们使用,也可以创建另一个房间,供下棋的两个人使用。
我们将通过标记号码来区别待机室与下棋室。
即用0标记待机室,其它房间使用0以上的自然数来标记。
如图1.2.1,客户机向服务器发送消息(a),与客户机连接的线程将收到的消息转发给消息广播者(b)。
然后,消息广播者会负责跟踪具有与客户机1相同的房间号的线程,并将消息传播给它们。
图1.2.1
1.3课程设计过程
1)理论知识学习:
本课程设计主要参考谢希仁编著的《计算机网络(第6版)》[1],语言方面采用的是徐明浩[韩]编著的《Java编程基础,应用与实例》[2]。
理论知识是一切研究设计的基础,所以扎实基础为研究设计的第一步,然后才开始进行设计。
2)分析和撰写文档:
本课程设计的大体分为创建通讯协议,网络五子棋游戏服务器端,网络五子棋游戏客户端三部分的设计。
编写好程序代码,进行编译,发现问题并且解决问题。
3)分析结果并得出结论:
最后一部分则是对编码编译,执行,看是否达到预期效果,若没有达到,则根据运行结果思考今后编程中需要注意的问题,代码格式和规范等。
1.4编程环境
1)软件方面:
测试程序在Windows7下的Myeclipse10.0环境中编写并测试。
2)硬件方面:
测试数据的生成及结果在第4代CPU酷睿i5-4200U、AMDRadeonHD
8670M、4GB内存的微机生成和通过。
3)编程语言:
选用语言为Java。
2总体设计与实现
2.1通信协议
为保证服务器与客户机正常的通信,我们需要确定所交换的信息属于何种类型。
例如,客户机向服务器提出进入某个房间的请求后,服务器必须确认所请求的房间是否允许它进入,然后,发送相应的消息给客户机。
对于消息,我们可以采用“[消息类型]+内容”的形式。
假若想进入第20号房间,那么,它需要向服务器发送消息“[ROOM]20”。
如果第20号房间允许进入,那么,服务器在进行了某些处理后会向客户机传送消息“[ROOM]20”。
相反,若20号房间禁止入内,则服务器将向客户机发送“[FULL]”消息。
游戏中的消息类型见表2.1.1和表2.1.2。
表2.1.1客户机的消息
客户机端消息类型
说明
[NAME]小明
发送玩家的名字
[ROOM]20
请求进入20号房间
[MSG]字符串
发送聊天信息
[START]
通知已做好游戏开始的准备
[DROPGAME]
宣布弃权
[STONE]57
通知将妻子置于(5,7位置)
[WIN]
宣布获胜
[STOPGAME]
通知终止游戏
表2.1.2服务器的消息
服务器端消息类型
[EXIT]小明
通告小明退出房间
[ENTER]小明
通告小明进入房间
通知对方已在(5,7)位置放置了棋子
[COLOR]BLACK
通知开始时,通知黑棋已被选中
[COLOR]WHITE
游戏开始时,通知白棋已被选中
通知玩家已经进入20号房间
[FULL]
通知房间都已满员
通知对方已弃权
通告已经获胜
[LOSE]
通知游戏失败
[DISCONNECT]
通知对方已经掉线
[PLAYER]
发送当前房间中的用户名
名字间使用tab键分割
例:
[PLAYER]小明\t小红\t小花
2.2五子棋游戏服务器端
服务器端主要有3个类:
OmokServer类、Omok_Thread类(线程类)、和BManager类
(消息广播者)。
OmokServer类在收到客户机的连接请求后,将创建新的套接字,并使其与客户机连接,然后启动线程,并将线程添加至BManager对象中。
PrivateBManagerbMan==newBManager();
//消息广播者对象
…
While(true){
Socketsocket=server.accept();
//获取套接字
Omok_Threadot=newOmok_Thread(socket);
//创建线程
ot.start();
//启动线程
bMan.add(ot);
//添加线程
}
Omok_Thread对象不仅可以获取套接字、输入输出流,而且它还提供了有关客户机的信息,例如客户机的名称、房间号、游戏开始与否等。
这是因为我们需要确定消息的来源及要在某个房间传播的消息。
并且,消息广播者也需要参照线程对象的房间号,以便将消息发送至某个房间中。
2.3五子棋客户端
客户端首先要实现五子棋盘(OmokBoard类)。
五子棋盘继承了画布类,它内嵌于框架窗口中,拥有15*15个格子。
为了响应用户的下棋动作,五子棋盘必须能够响应鼠标事件,并且它必须拥有输出流,用以向对手传递当前棋手的下棋信息。
程序中也有多种方法用来实现绘图操作。
然而,程序中最重要的部分就是如何决定胜负。
横、竖或者对角线向上拥有五颗同颜色的棋子时,即为胜利。
看图2.3.1,首先在1、2、3、4号位置各放置一颗黑色棋子。
如果黑方最后一颗棋子放在5号位置,则黑方在横向上五子连珠,黑方胜。
程序的实现:
在放下5号棋子后,首先程序要计算出它左边连在一起的黑色棋子个数。
其左边已放有1、2和3号棋子,且都是连在一起的,所以5号棋子左边相连的黑色棋子有一颗。
然后,再计算5号棋子右边连在一起的黑色棋子个数。
如图,5号棋子右边有4号。
因此,5号棋子左边、右边还有其本身合起来总共五颗黑色棋子,黑方获胜。
图2.3.1
map是一个二元数组,用于保存棋子的位置。
如果在(2,3)位置上有一颗黑色棋子,则向数组元素map[2][3]赋入BLACK(=1);
若为白棋,则将WHITE(=-1)值代入。
并且,如果某个位置没有任何棋子,则向对应的数组元素中赋0值。
map[2][3]=BLACK;
//在(2,3)位置上,放置黑色棋子
map[5][5]=WHITE;
//在(5,5)位置上,放置白色棋子
map[10][10]=0;
//在(10,10)位置上,没有棋子
count()方法用来查找并计算连载一起的棋子的个数。
p为基准坐标,dx、dy分别为表示横向与竖向的变量。
col代表棋子的颜色。
若dx为-1,dy为0,则计算左边连续棋子的个数;
若dx为1,dy为1,则计算左下到右上对角线方向上连续棋子的个数。
dx与dy只取-1、0、1三个值之一。
下面是count()方法的代码。
privateintconut(pointp,intdx,intdy,intcol){
inti=0;
for(;
map[p.x+(i+1)*dx][p.y+(i+1)*dy]==col;
i++)
{}
return1;
check()方法会调用count()方法,用来判断是否五子连珠。
其代码如下。
privatebooleancheck(pointp,intcol){
if(count(p,1,0,col)+count(p,-1,0,col)==4)//横向检查
returntrue;
if(count(p,0,1,col)+count(p,0,-1,col)==4)//竖向检查
if(count(p,-1,-1,col)+count(p,1,1,col)==4)//对角线方向检查
if(count(p,1,-1,col)+count(p,-1,1,col)==4)//对角线方向检查
returnfalse;
3.程序的测试
3.1服务器端的建立
在Myeclipse10.0中运行服务器代码,截图如图3.1.1。
图3.1.1
3.2客户机端的运行
在Myeclipse10.0中执行客户机代码,截图如图3.2.1。
右下角显示已经连接到服务器。
图3.2.1
3.3五子棋游戏完整执行
在Myeclipse10.0中完整执行游戏,如图3.3.1
图3.3.1
双方进行下棋,并且在右下方进行了通讯。
4.结束语
Java作为一种分布式和可移植的计算机语言,在网络软件开发上有着特别的优点。
它开发方便、快捷,安全性高,对以往复杂的功能,尤其是网络通信等方面,实现起来简洁明了,在网络编程领域有着巨大的发展潜力。
这次Java课程设计完成了一个网络五子棋的设计和开发。
包括服务器和客户端。
不同的用户使用客户端,利用服务器相连。
实现了用户在Internet上任何地方与别人进行五子对战。
网络五子棋的实现用到了网络套接字和多线程的相关知识。
服务器创建服务器Socket,并处于监听状态。
客户端向服务器发出申请,服务器接受后,利用输入输出流进行通信。
并开始一个线程,处理与这个相连的客户端在游戏过程的数据传输、控制等。
进行五子棋的一个主要算法就是判断输赢。
这里采用计算落下棋子的横、竖及对角线方向的同色棋子的个数来实现。
当个数为5时为胜。
服务器与客户端在通信过程中,双方如何知道发送信息的意义呢?
这里发送的信息采用“[消息类别]+内容“的格式。
服务器和客户端通过分析“消息类别”来采取不同的方法处理发送的数据。
通过这次课程设计,加深了我对Java网络编程和多线程编程方面的了解。
网络五子棋基本实现了网络对战的功能,但只能通过网络,没有实现人机对战的功能。
也没有添加“禁手”规则。
这时是已后要改进的地方。
参考文献
[1]谢希仁计算机网络(第6版).电子工业出版社,2013
[2](韩)徐明浩Java编程基础、应用与实例.人民邮电出版社,2006
[3]王吴迪,赵枫朝Java开发与应用.电子工业出版社,2006
附录程序代码
OmokServer.java
import.*;
importjava.io.*;
importjava.util.*;
publicclassOmokServer{
privateServerSocketserver;
privateBManagerbMan=newBManager();
privateRandomrnd=newRandom();
publicOmokServer(){}
voidstartServer(){
try{
server=newServerSocket(7777);
System.out.println("
服务器套接字已被创建."
);
while(true){
Socketsocket=server.accept();
Omok_Threadot=newOmok_Thread(socket);
ot.start();
bMan.add(ot);
连接数:
"
+bMan.size());
}
}catch(Exceptione){
System.out.println(e);
publicstaticvoidmain(String[]args){
OmokServerserver=newOmokServer();
server.startServer();
classOmok_ThreadextendsThread{
privateintroomNumber=-1;
privateStringuserName=null;
privateSocketsocket;
privatebooleanready=false;
privateBufferedReaderreader;
privatePrintWriterwriter;
Omok_Thread(Socketsocket){
this.socket=socket;
SocketgetSocket(){
returnsocket;
intgetRoomNumber(){
returnroomNumber;
StringgetUserName(){
returnuserName;
booleanisReady(){
returnready;
publicvoidrun(){
reader=newBufferedReader(newInputStreamReader(socket.getInputStream()));
writer=newPrintWriter(socket.getOutputStream(),true);
Stringmsg;
while((msg=reader.readLine())!
=null){
if(msg.startsWith("
[NAME]"
)){
userName=msg.substring(6);
}
elseif(msg.startsWith("
[ROOM]"
introomNum=Integer.parseInt(msg.substring(6));
if(!
bMan.isFull(roomNum)){
if(roomNumber!
=-1)
bMan.sendToOthers(this,"
[EXIT]"
+userName);
roomNumber=roomNum;
writer.println(msg);
writer.println(bMan.getNamesInRoom(roomNumber));
[ENTER]"
elsewriter.println("
[FULL]"
elseif(roomNumber>
=1&
&
msg.startsWith("
[STONE]"
))
bMan.sendToOthers(this,msg);
[MSG]"
bMan.sendToRoom(roomNumber,"
["
+userName+"
]:
+msg.substring(5));
[START]"
ready=true;
if(bMan.isReady(roomNumber)){
inta=rnd.nextInt
(2);
if(a==0){
writer.println("
[COLOR]BLACK"
[COLOR]WHITE"
else{
[STOPGAME]"
ready=false;
[DROPGAME]"
[WIN]"
[LOSE]"
}finally{
bMan.remove(this);
if(reader!
=null)reader.close();
if(writer!
=null)writer.close();
if(socket!
=null)socket.close();
reader=null;
writer=null;
socket=null;
System.out.println(userName+"
已断线."
连接人数:
bMan.sendToRoom(roomNumber,"
[DISCONNECT]"
}catch(Exceptione){}
classBManagerextendsVector{
BManager(){}
voidadd(Omok_Threadot){
super.add(ot);
voidremove(Omok_Threadot){
super.remove(ot);
Omok_ThreadgetOT(inti){
return(Omok_Thread)elementAt(i);
SocketgetSocket(inti){
returngetOT(i).getSocket();
voidsendTo(inti,Stringmsg){
PrintWriterpw=newPrintWriter(getSocket(i).getOutputStream(),true);
pw.println(msg);
}catch(Exceptione){}
intgetRoomNumber(inti){
returngetOT(i).getRoomNumber();
synchronizedbooleanisFull(introomNum){
if(roomNum==0)returnfalse;
intcount=0;
for(inti=0;
i<
size();
if(roomNum==getRoomNumber(i))count++;
if(count>
=2)returntrue;
voidsendToRoom(introomNum,Stringmsg){
if(roomNum==getRoomNumber(i))
sendTo(i,msg);
voidsendToOthers(Omok_Threadot,Stringmsg){
if(getRoomNumber(i)==ot.getRoomNumber()&
getOT(i)!
=ot)
synchronizedbooleanisReady(introomNum){
if(roomNum