JavaNIO開發的猜大小遊戲

學習一下javaNIO用法,就開發了個簡單的小遊戲,猜大小,服務端用javaNIO api寫的,客戶端用的普通的socket,一個服務端支持多個客戶端!每個客戶端猜大還是小,然後由管理員控制開始猜測然後通知所有玩家。。。使用NIO傳送數據,ByteBuffer需要用characterEncoding編碼才行,要不然對方收不到。
這是服務端代碼:
 
package game;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

/**
* 服務端
* @version 1.0 2011-4-27
*/
public class BigSmallServer {
protected Charset charset = Charset.forName("UTF-8");
protected CharsetEncoder charsetEncoder = charset.newEncoder();
protected CharsetDecoder charsetDecoder = charset.newDecoder();
private Selector selector = null;
List<Player> players = new ArrayList<Player>();
public static void main(String[] args) throws Exception{
new BigSmallServer().run();
}
public void print(Object o){
System.out.println(new Date().toLocaleString()+":"+o);
}
public void run() throws Exception{
selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ServerSocket serverSocket = ssc.socket();
serverSocket.bind(new InetSocketAddress(8888));
ssc.configureBlocking(false);
ssc.register(selector, SelectionKey.OP_ACCEPT);

while(true){
int nKeys = selector.select();
if(nKeys > 0){
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while(it.hasNext()){
SelectionKey key = it.next();
if(key.isAcceptable()){
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel channel = server.accept();
if (channel == null) {
continue;
}
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
print("客戶端:"+channel.socket().getRemoteSocketAddress()+" 建立連接...");
Player player = new Player();
player.id = channel.socket().getRemoteSocketAddress().toString();
player.sc = channel;
players.add(player);
}
if(key.isReadable() ){
this.readDataFromSocket(key);
}
it.remove();
}//end while
}//end if
}//end while
}

private void readDataFromSocket(SelectionKey key) throws IOException {

ByteBuffer buf = ByteBuffer.allocate(1024);
SocketChannel sc = (SocketChannel) key.channel();
print("客戶端:"+sc.socket().getRemoteSocketAddress()+" 讀取數據...");
Player player = null;
for(Player p: players){
if(p.id.equals(sc.socket().getRemoteSocketAddress().toString()))
{
player = p;break;
}
}
int readBytes = 0;
int ret;

try {
while ((ret = sc.read(buf)) > 0) {
readBytes += ret;
}
if(readBytes <= 0){
sc.close();
}
} finally {
buf.flip();
}

// String s = new String(buf.array());
// System.out.println(sb.toString());
String msg = charsetDecoder.decode(buf).toString();
String[] cmds = msg.split(":");
String cmd = cmds[0];
if("name".equals(cmd)){
player.name = cmds[1];
if(player.name.equals("admin")){
player.bAdmin = true;
}
sc.write(charsetEncoder.encode(CharBuffer.wrap( "ok:"+player.bAdmin + "\n")));
print(player.id+" 暱稱:"+player.name);
}
if("guess".equals(cmd)){
//得到猜測數據
player.guess = cmds[1].charAt(0);
sc.write(charsetEncoder.encode(CharBuffer.wrap( "guessok\n")));
print(player.name+" 猜測:" + player.guess);
//通知管理員有多少個人猜測了
}
if("start".equals(cmd)){
//開始,所有的guess設置爲空
if(player.bAdmin){
//通知所有客戶端可以開始了
for(Player p: players){
if(p.bAdmin)continue;//管理員不玩
p.guess = 0;
p.sc.write(charsetEncoder.encode(CharBuffer.wrap("start\n")));
}
}
}
if("result".equals(cmd)){
//得結果通知所有人
if(player.bAdmin){
float f = 0.5000F;//大的概率
boolean rs = this.getTrueFalse(f);

String res = "";
int cWin = 0, cLoss = 0;
for(Player p: players){
if(p.bAdmin)continue;//管理員不玩
if(rs && p.guess == 'b'){
cWin++;
}else if(!rs && p.guess == 's'){
cWin++;
}else{
cLoss++;
}
}

for(Player p: players){
if(p.bAdmin)continue;//管理員不玩
if(rs && p.guess == 'b'){
res ="result:勝利,結果爲大,積分="+(++p.score)+",本局贏/輸的人數爲:"+cWin+"/"+cLoss;
}else if(!rs && p.guess == 's'){
res ="result:勝利,結果爲小,積分="+(++p.score)+",本局贏/輸的人數爲:"+cWin+"/"+cLoss;
}else{
res ="result:失敗,結果爲"+(rs?"大":"小")+",積分="+(--p.score)+",本局贏/輸的人數爲:"+cWin+"/"+cLoss;
}
p.sc.write(charsetEncoder.encode(CharBuffer.wrap( res+"\n")));
}
}
}
// process buffer
// buf.clear();

}
/**
* 以rand的概率返回true
* rand範圍是0.01%-99.99%。即0.0001-0.9999
*/
public boolean getTrueFalse(float r){
Random rand = new Random();
int v = (int) (r * 10000);
if(v < 0 || v > 10000)throw new RuntimeException("out of range");
rand.setSeed(System.nanoTime()+v);
int r1 = rand.nextInt(10000) + v;
return r1 - 10000 >=0 ?true:false;
}
static class Player{
public String name;
public String id;
public int score;
public boolean bAdmin;//只有管理員有權限決定開始
public char guess;//猜測的大小
public SocketChannel sc;//
}
}


這是客戶端代碼:


package game;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Date;

/**
* 客戶端
* @version 1.0 2011-4-27
*/
public class BigSmallClient {
public void print(Object o){
System.out.println(new Date().toLocaleString()+":"+o);
}
public static void main(String[] args) throws Exception{
new BigSmallClient().run();
}

public void run()throws Exception{
Socket s = new Socket("172.16.1.134", 8888);
print("連接服務器成功..."+s.getRemoteSocketAddress().toString());
print("請輸入大名:");
InputStream ins = s.getInputStream();
BufferedReader sbr = new BufferedReader(new InputStreamReader(ins));
BufferedReader inbr = new BufferedReader(new InputStreamReader(System.in));
OutputStream os = s.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
String line = inbr.readLine();
bw.write("name:"+line);
bw.flush();
line = sbr.readLine();
String[] cmds = line.split(":");
if(cmds[0].equals("ok")){
if("true".equals(cmds[1])){
while(true){
print("輸入命令(start,result)...");
line = inbr.readLine();
if("start".equals(line)){
bw.write("start");
bw.flush();
}else if("result".equals(line)){
bw.write("result");
bw.flush();
}else if("q".equals(line)){
break;
}
}
}else{
print("設置成功,請等待開始...");
line = sbr.readLine();
do{
cmds = line.split(":");
if(cmds[0].equals("start")){
print("可以開始了,大(b),小(s),退出(q)?");
line = inbr.readLine();
if(line.equals("q"))break;
bw.write("guess:"+line);
bw.flush();
line = sbr.readLine();
continue;
}
if(cmds[0].equals("guessok")){
print("猜測成功,等待結果...");
line = sbr.readLine();
continue;
}
if(cmds[0].equals("result")){
print("結果:"+cmds[1]);
line = sbr.readLine();
continue;
}
}while(true);
}
}

s.close();
}

}


發佈了21 篇原創文章 · 獲贊 0 · 訪問量 3534
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章