?? serverframe.java
字號:
import javax.swing.JFrame;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.BorderLayout;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JButton;
import java.awt.Color;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.PrintStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.StringTokenizer;
public class ServerFrame extends JFrame implements ActionListener{
JScrollPane scrollPane=new JScrollPane();
JTextArea logTextArea=new JTextArea(); //記錄服務(wù)器事務(wù)的文本編輯框
JButton shutdownButton=new JButton("關(guān)閉服務(wù)器"); //關(guān)閉按鈕
//
int serverInPort=6817; //服務(wù)器的輸入端口
int serverOutPort=6818; //服務(wù)器的輸出端口
ServerSocket sInSocket; //輸入套接字
ServerSocket sOutSocket; //輸出套接字
//
SRThread srThread;
//初始化對弈情況表(共兩張臺,每張臺有兩張椅子,初始狀態(tài)為未入座,IP、Socket等暫時為null.)
TableStatus[] tableStatus={new TableStatus(),new TableStatus()};
public ServerFrame(){
setTitle("互聯(lián)網(wǎng)多人聯(lián)機對弈(井字棋)游戲服務(wù)器");
setSize(500,300);
//添加帶水平、垂直滾動條的滾動面板
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
getContentPane().add(scrollPane,BorderLayout.CENTER);
//設(shè)置文本框?qū)傩? logTextArea.setEditable(false); //只讀
logTextArea.setBackground(Color.black); //背景為黑色
logTextArea.setForeground(Color.white); //字體為白色
scrollPane.getViewport().setView(logTextArea); //使文本編輯框具有滾動條
//添加"關(guān)閉服務(wù)器"按鈕
getContentPane().add(shutdownButton,BorderLayout.SOUTH);
show();
//
try{
sInSocket=new ServerSocket(serverInPort); //創(chuàng)建用于服務(wù)器輸入的套接字
sOutSocket=new ServerSocket(serverOutPort); //創(chuàng)建用于服務(wù)器輸出的套接字
}catch(IOException e){
System.out.println("創(chuàng)建服務(wù)器ServerSocket失敗");
System.exit(1); //退出服務(wù)器
}
//啟動讀數(shù)據(jù)線程
srThread=new SRThread();
srThread.start();
//添加"關(guān)閉服務(wù)器"按鈕的單擊事件監(jiān)聽器
shutdownButton.addActionListener(this);
}
public void actionPerformed(ActionEvent e){
dispose();
System.exit(0);
}
public void finalize(){
try{
sInSocket.close();
sOutSocket.close();
}catch(IOException e2){System.out.println("關(guān)閉套接字失敗");}
sInSocket=null;
sOutSocket=null;
srThread=null;
}
public static void main(String[] args){
ServerFrame serverFrame=new ServerFrame();
}
public void log(String s){ //在文本框顯示服務(wù)器工作日志
logTextArea.append(s+"\n"); //主動換行
}
public void setChairIdle(int tableNum,int chairNum){
tableStatus[tableNum].chairStatus[chairNum]=0;
tableStatus[tableNum].ip[chairNum]=null;
tableStatus[tableNum].sWriter[chairNum]=null;
}
public void setChairOn(int tableNum,int chairNum,String sIp,PrintStream writer){
tableStatus[tableNum].chairStatus[chairNum]=1; //已被坐上
tableStatus[tableNum].ip[chairNum]=sIp;
tableStatus[tableNum].sWriter[chairNum]=writer;
}
public void sendOnSeatMan(String msg){ //將msg消息發(fā)送到已坐下,但還未開始對弈的所有客戶.
for(int tNum=0;tNum<2;tNum++){
for(int cNum=0;cNum<2;cNum++){
if(tableStatus[tNum].chairStatus[cNum]==1 && tableStatus[tNum].playStatus!=3 && tableStatus[tNum].playStatus!=4){
tableStatus[tNum].sWriter[cNum].println(msg);
}
}
}
}
class TableStatus{
int[] chairStatus={0,0}; //對應(yīng)兩張椅子的入座狀態(tài)(0表示空出,1表示已入座)
int playStatus=2; //臺面狀態(tài)(2表示未開始對弈,0表示上方座位下先手棋,1則表示下方座位為先手棋,3表示正申請重新對弈,4表示有一方已離座)
String[] ip={null,null}; //對應(yīng)兩張椅子的入座機器IP
PrintStream[] sWriter={null,null}; //對應(yīng)于兩張椅子上服務(wù)器端的數(shù)據(jù)輸出流
}
class SRThread extends Thread{ //Server Read 讀線程
public void run(){
while(true){
try{ //利用ServerSocket套接字監(jiān)聽客戶端,并創(chuàng)建一個與客戶端連接對應(yīng)的套接字。
synchronized(this){
Socket cInSocket=sInSocket.accept();
Socket cOutSocket=sOutSocket.accept();
ChildThread childThread=new ChildThread(cInSocket,cOutSocket);
childThread.start();
}
}catch(IOException e){
System.out.println("創(chuàng)建與客戶端連接的套接字失敗.");
System.exit(2); //退出服務(wù)器
}
}
}
}
class ChildThread extends Thread{
Socket cInSocket; //用于讀入客戶端數(shù)據(jù)的服務(wù)器端套接字
Socket cOutSocket; //用于寫入客戶端數(shù)據(jù)的服務(wù)器端套接字
PrintStream sWriter;
BufferedReader sReader;
String receiveMsg;
StringTokenizer st;
int tableNum,chairNum; //此線程所對應(yīng)的客戶的臺號、椅子號
int cellIndex; //棋格號
String sIp;
ChildThread(Socket cInSocket,Socket cOutSocket){
this.cInSocket=cInSocket;
this.cOutSocket=cOutSocket;
//取得對應(yīng)的輸出流,發(fā)送入座信息到客戶端,以初始化客戶端界面。
try{
sWriter=new PrintStream(cOutSocket.getOutputStream());
synchronized(tableStatus){ //同步該語句塊
for(int tNum=0;tNum<2;tNum++){ //發(fā)送格式"seat:臺號,椅子號,入座狀態(tài)"數(shù)據(jù)到客戶端
for(int cNum=0;cNum<2;cNum++){
sWriter.println("seat:"+tNum+","+cNum+","+tableStatus[tNum].chairStatus[cNum]);
}
}
}
log(cInSocket.getInetAddress().getHostAddress()+"連接上來,但未入座."); //寫服務(wù)器日志
//初始化輸入流sReader
sReader=new BufferedReader(new InputStreamReader(cInSocket.getInputStream()));
}catch(IOException e){
System.out.println("線程創(chuàng)建輸入輸出流失敗"+e);
}
}
public void run(){
while(true){
try{
receiveMsg=sReader.readLine();
}catch(IOException e){
System.out.println("讀數(shù)據(jù)IO出錯.");
break; //使線程死亡
}
if(receiveMsg.startsWith("logout:")){ //注銷座位
receiveMsg=receiveMsg.substring(7,receiveMsg.length());
st=new StringTokenizer(receiveMsg,",");
try{
while(st.hasMoreTokens()){
tableNum=Integer.parseInt(st.nextToken());
chairNum=Integer.parseInt(st.nextToken());
}
}catch(NumberFormatException e){}
if(tableNum!=-1 && chairNum!=-1){ //不是首次入座位
synchronized(tableStatus){ //同步該語句塊
sendOnSeatMan("seat:"+tableNum+","+chairNum+",0"); //刷新在坐的客戶臺面
setChairIdle(tableNum,chairNum); //設(shè)置座位空閑
}
}
}
else if(receiveMsg.startsWith("login:")){ //座位申請注冊
receiveMsg=receiveMsg.substring(6,receiveMsg.length());
st=new StringTokenizer(receiveMsg,",");
try{
while(st.hasMoreTokens()){
tableNum=Integer.parseInt(st.nextToken());
chairNum=Integer.parseInt(st.nextToken());
}
}catch(NumberFormatException e){}
sIp=cInSocket.getInetAddress().getHostAddress();
synchronized(tableStatus){ //同步該語句塊
if(tableStatus[tableNum].chairStatus[chairNum]==0){ //該座位未被坐下
//登記對弈情況表的tableNum號臺、chairNum號椅子的信息
setChairOn(tableNum,chairNum,sIp,sWriter);
//立即刷新入坐者
sendOnSeatMan("seat:"+tableNum+","+chairNum+",1");
log(sIp+"申請座位成功.已坐下"+tableNum+"號臺,"+chairNum+"號椅子.");
}
else{ //如果客戶端申請一個已被占用的座位,login失敗.
sWriter.println("no seat!"); //向此客戶端發(fā)送座位被占用信息
}
}
}
else if(receiveMsg.startsWith("play!")){ //處理對弈請求
synchronized(tableStatus){ //同步該語句塊
//對方已入座,才可開始對弈,并且該臺號仍為未開始對弈狀態(tài)(這個判斷可以阻止雙方競爭先手棋).
if(tableStatus[tableNum].chairStatus[1-chairNum]==1 && tableStatus[tableNum].playStatus==2){
tableStatus[tableNum].playStatus=chairNum; //設(shè)置正在對弈狀態(tài)和下先手棋的一方
//發(fā)送臺號到對弈雙方,表示對弈開始.
sWriter.println("start:"+chairNum); //發(fā)送給請求對弈者,chairNum表示先下棋的椅子號.
tableStatus[tableNum].sWriter[1-chairNum].println("start:"+chairNum); //發(fā)送給對方
}
}
}
else if(receiveMsg.startsWith("go:")){ //處理對方棋步
receiveMsg=receiveMsg.substring(3,receiveMsg.length());
try{
cellIndex=Integer.parseInt(receiveMsg);
}catch(NumberFormatException e){}
tableStatus[tableNum].sWriter[1-chairNum].println("chess:"+cellIndex); //向?qū)姆睫D(zhuǎn)發(fā)落子所在的棋格號
}
else if(receiveMsg.startsWith("win:")){ //收到嬴棋信息
receiveMsg=receiveMsg.substring(4,receiveMsg.length());
try{
cellIndex=Integer.parseInt(receiveMsg);
}catch(NumberFormatException e){}
tableStatus[tableNum].sWriter[1-chairNum].println("defeat:"+cellIndex); //轉(zhuǎn)發(fā)對弈方輸棋信息
}
else if(receiveMsg.startsWith("peace:")){ //收到和局信息
receiveMsg=receiveMsg.substring(6,receiveMsg.length());
try{
cellIndex=Integer.parseInt(receiveMsg);
}catch(NumberFormatException e){}
tableStatus[tableNum].sWriter[1-chairNum].println("chess:"+cellIndex);
tableStatus[tableNum].sWriter[1-chairNum].println("peace!"); //通知這局棋和了
}
else if(receiveMsg.startsWith("talk:")){ //收到棋盤滿子的信息
receiveMsg=receiveMsg.substring(5,receiveMsg.length());
tableStatus[tableNum].sWriter[1-chairNum].println("message:"+receiveMsg); //轉(zhuǎn)發(fā)對弈方轉(zhuǎn)發(fā)聊天話本
}
else if(receiveMsg.startsWith("restart!")){ //收到重新開棋對弈請求
if(tableStatus[tableNum].playStatus!=3 && tableStatus[tableNum].playStatus!=4){ //對方并未申請重新開棋或?qū)Ψ轿措x開(避免雙方競爭重新開棋)
tableStatus[tableNum].playStatus=3; //設(shè)置該臺正被申請重新對弈的狀態(tài)
tableStatus[tableNum].sWriter[1-chairNum].println("again?"); //向?qū)姆桨l(fā)送重新開棋請求
}
}
else if(receiveMsg.startsWith("agree!")){ //收到同意重新開棋信息
receiveMsg=receiveMsg.substring(6,receiveMsg.length());
tableStatus[tableNum].playStatus=1-chairNum; //表明1-chairNum椅子執(zhí)子先行的(實際使該狀態(tài)不為3).
tableStatus[tableNum].sWriter[1-chairNum].println("agree!"); //向請求者轉(zhuǎn)發(fā)同意重新開局信息
}
else if(receiveMsg.startsWith("go back!")){ //收到返回游戲大廳信息
tableStatus[tableNum].sWriter[1-chairNum].println("go back!"); //向?qū)姆揭舶l(fā)送返回信息
//該臺號的兩張椅子恢復(fù)可用,但不關(guān)閉Socket等資源.
setChairIdle(tableNum,chairNum);
setChairIdle(tableNum,1-chairNum);
tableStatus[tableNum].playStatus=2; //恢復(fù)該臺號狀態(tài)為未開始對弈
//通知在坐、但還未開棋的客戶該臺面(兩張椅子)已可用
sendOnSeatMan("seat:"+tableNum+","+chairNum+",0");
sendOnSeatMan("seat:"+tableNum+","+(1-chairNum)+",0");
}
else if(receiveMsg.startsWith("refresh!")){ //收到刷新客戶端臺面請求
synchronized(tableStatus){ //同步該語句塊
for(int tNum=0;tNum<2;tNum++){ //發(fā)送所有臺面、椅子的入座信息
for(int cNum=0;cNum<2;cNum++){
sWriter.println("refresh:"+tNum+","+cNum+","+tableStatus[tNum].chairStatus[cNum]);
}
}
}
}
else if(receiveMsg.startsWith("exit:")){ //收到客戶退出信息
receiveMsg=receiveMsg.substring(5,receiveMsg.length());
st=new StringTokenizer(receiveMsg,",");
try{
while(st.hasMoreTokens()){
tableNum=Integer.parseInt(st.nextToken());
chairNum=Integer.parseInt(st.nextToken());
}
}catch(NumberFormatException e){}
if(tableNum!=-1 && chairNum!=-1){ //此客戶已坐下的情形
if(tableStatus[tableNum].playStatus==0 || tableStatus[tableNum].playStatus==1){ //客戶已開始對弈的情形
//讓同臺的對弈方返回游戲大廳
tableStatus[tableNum].sWriter[1-chairNum].println("she exit!");
}
//讓其他已入座、但未開始對弈的客戶刷新臺面(不發(fā)給自己)
for(int tNum=0;tNum<2;tNum++){
for(int cNum=0;cNum<2;cNum++){
if(((tNum!=tableNum)||(cNum!=chairNum)) && (tableStatus[tNum].chairStatus[cNum]==1 && tableStatus[tNum].playStatus!=3 && tableStatus[tNum].playStatus!=4)){
tableStatus[tNum].sWriter[cNum].println("seat:"+tableNum+","+chairNum+",0");
}
}
}
//恢復(fù)該客戶的臺面、椅子未入座
tableStatus[tableNum].sWriter[chairNum].close();
setChairIdle(tableNum,chairNum); //設(shè)置退出者座位為空
tableStatus[tableNum].playStatus=2; //該臺還未開始對弈
log(sIp+"客戶:("+tableNum+"號臺,"+chairNum+"號椅子)退出了游戲");
break; //退出客戶線程
}
else{ //該客戶并未取得座位
break; //直接退出客戶線程
}
}
}
}
public void finalize(){ //釋放線程資源
try{
cInSocket.close();
cOutSocket.close();
sReader.close();
sWriter.close();
}catch(IOException e){
System.out.println("關(guān)閉線程的資源出現(xiàn)錯誤"+e);
}
cInSocket=null;
cOutSocket=null;
sReader=null;
sWriter=null;
}
}
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -