오목 서비스를 제공하기 위한 서버측 프로그램이다.
클라이언트 접속을 기다리고 접속이 발생할 경우 연결 쓰레드를 생성해 할당한다.
접속된 클라이언트를 Vector로 저장되며, 로그아웃시 Vector에서 삭제된다.
import java.io.*;
import java.net.*;
import java.util.*;
public class flashServer{
ServerSocket server;
Socket ckt;
final int PORT= 9040;
broadCast bc= new broadCast(); //클라이언트 들에게 이벤트 메세지를 브로드캐스팅해주는 클레스
public void startServer(){
try{
server= new ServerSocket(PORT);
try{
while(true){
ckt= server.accept(); //클라이언트 접속을 기다린다. 요청이 발생하면 밑의 구문이 실행된다.
cThread ct= new cThread(ckt, bc);
ct.start();//클라이언트 쓰레드 생성후 실행.
bc.add(ct);//브로드캐스팅을 위한 클래스에 클라이언트 쓰레드를 넘겨준다.
System.out.println("Connected From :"+ckt);
System.out.println("쓰레드 생성 :"+ct);
}
}catch(Exception e){
System.err.println("클라이언트 접속 끊김");
server.close();
}
}catch(Exception e){
System.err.println("서버소켓생성실패 :"+e);
}
}
public static void main(String args[]){
flashServer fs= new flashServer();
fs.startServer();
}
};
class cThread extends Thread{//클라이언트와 통신할 쓰레드.
int roomNumber= -1;//최초의 방번호는 -1
String userName= null;//접속시 사용한 사용자 이름
boolean ready= false;//방 입장 후 게임 준비 여부.
BufferedReader reader;//쓰레드와 연결된 클라이언트의 명령을 읽는다.
PrintWriter writer;//다른 사용자에게 이벤트 메세지를 전송할 변수.
Socket socket;
broadCast bc;
public cThread(Socket s, broadCast bc){
socket= s;
try{
reader= new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer= new PrintWriter(socket.getOutputStream());
this.bc=bc;
}catch(Exception e){
System.err.println("스트림 생성 에러 :"+e);
}
}
public Socket getSocket(){
return socket;
}
public int getRoomNumber(){
return roomNumber;
}
public String getUserName(){
return userName;
}
public boolean isReady(){
return ready;
}
public void sendToMe(String str){
writer.write(str+'\0');
writer.flush();
}
public void run(){
String msg;
try{
while(true){
if((msg=reader.readLine())!=null){
System.out.println("받은 메세지 :"+msg);
msgSlice(msg);//메세지 전송을 위해 정규화 시킨다.
reader.skip(1);//문자열 끝에 newline이 포함되어 있으므로 한문자 스킵시킨다
}else{
break;
}
}
}catch(Exception e){
System.out.println("메세지 읽기 에러 :"+e);
}finally{
try{
//모든 변수를 초기화 시킨다.
System.out.println("클라이언트 접속 끊김");
bc.remove(this);
bc.sendToRoom(roomNumber,"out:"+userName);
if(reader!=null){ reader.close(); reader=null; }
if(writer!=null){ writer.close(); writer=null; }
if(socket!=null){ socket.close(); socket=null; }
}catch(Exception e){
System.err.println("소켓 제거 에러 :"+e);
}
}
}
public void msgSlice(String msg) throws Exception{
if(msg.startsWith("name:")){
userName=msg.substring(5);
}else if(msg.startsWith("room:")){
int roomNum=Integer.parseInt(msg.substring(5));
if( !bc.isFull(roomNum)){
if(roomNumber!=-1){
//같은 방의 다른 사람에게 나의 퇴장을 알려준다.
bc.sendToOthers(this, "exit:"+userName);
}
roomNumber=roomNum;
// 사용자에게 먼저 접속해 있던 사람의 이름을 알려준다.
sendToMe(bc.getNamesInRoom(roomNumber, userName));
// 새 방에 있는 다른 사용자에게 자신이 입장했음을 알린다.
bc.sendToOthers(this, "enter:"+userName);
}else{
sendToMe("full:"); // 사용자에 방이 찼음을 알린다.
}
}else if(roomNumber>=1 && msg.startsWith("stone:")){
bc.sendToOthers(this, msg);
}else if(msg.startsWith("msg:")){
bc.sendToRoom(roomNumber, "msg:["+userName+"]"+msg.substring(4));
}else if(msg.startsWith("ready:")){
ready=true;
// 다른 사용자도 게임을 시작한 준비가 되었으면
if(bc.isReady(roomNumber)){
bc.sendToRoom(roomNumber, "start:");
}
}else if(msg.startsWith("stopGame:")){
ready=false;
}else if(msg.startsWith("dropGame:")){// 사용자가 게임을 기권하는 메시지를 보내면
ready=false;
// 상대편에게 사용자의 기권을 알린다.
bc.sendToOthers(this, "dropGame:");
}else if(msg.startsWith("win:")){
ready=false;
// 상대편에는 졌음을 알린다.
bc.sendToOthers(this, "lose:");
}
}
};
class broadCast{ // 메시지를 전달하는 클래스
Vector userVector= new Vector();
public void add(cThread ct){ // 스레드를 추가한다.
userVector.add(ct);
System.out.println(userVector.size());
}
public void remove(cThread ct){ // 스레드를 제거한다.
userVector.remove(ct);
}
public cThread getClient(int i){ // i번째 스레드를 반환한다.(cThread)elementAt(i)
return (cThread)userVector.elementAt(i);
}
public Socket getSocket(int i){ // i번째 스레드의 소켓을 반환한다.
return getClient(i).getSocket();
}
public int getRoomNumber(int i){ // i번째 스레드의 방 번호를 반환한다.
return getClient(i).getRoomNumber();
}
// i번째 스레드와 연결된 클라이언트에게 메시지를 전송한다.
public void sendTo(int i, String msg){
try{
PrintWriter pw= new PrintWriter(getSocket(i).getOutputStream(), true);
pw.write(msg+'\0');
pw.flush();
}catch(Exception e){}
}
synchronized boolean isFull(int roomNum){ // 방이 찼는지 알아본다.
if(roomNum==0)return false; // 대기실은 차지 않는다.
// 다른 방은 2명 이상 입장할 수 없다.
int count=0;
for(int i=0;i<userVector.size();i++)
if(roomNum==getRoomNumber(i))count++;
if(count>=2)return true;
return false;
}
// roomNum 방에 msg를 전송한다.
void sendToRoom(int roomNum, String msg){
for(int i=0;i<userVector.size();i++){
if(roomNum==getRoomNumber(i)){
sendTo(i, msg);
}
}
}
// ot와 같은 방에 있는 다른 사용자에게 msg를 전달한다.
void sendToOthers(cThread ct, String msg){
for(int i=0;i<userVector.size();i++){
if(getRoomNumber(i)==ct.getRoomNumber() && getClient(i)!=ct){
sendTo(i, msg);
}
}
}
// 게임을 시작할 준비가 되었는가를 반환한다.
// 두 명의 사용자 모두 준비된 상태이면 true를 반환한다.
synchronized boolean isReady(int roomNum){
int count=0;
for(int i=0;i<userVector.size();i++){
if(roomNum==getRoomNumber(i) && getClient(i).isReady()){
count++;
}
}
if(count==2)return true;
return false;
}
// roomNum방에 있는 사용자들의 이름을 반환한다.
public String getNamesInRoom(int roomNum, String userName){
StringBuffer sb=new StringBuffer("PLAYERS:");
for(int i=0;i<userVector.size();i++){
if(roomNum==getRoomNumber(i)){
if(getClient(i).getUserName().equals(userName)){
}else{
sb.append(getClient(i).getUserName());
}
}
}
return sb.toString();
}
}
'Computer > Java' 카테고리의 다른 글
[Data Structure2] Binary Tree (Linked List) (0) | 2006.10.09 |
---|---|
[Data Structure2] Max Heap (for int array) (0) | 2006.10.09 |
[tip] 화면 크기 구하기. (0) | 2006.08.04 |
Cyworld Today Counter Hack ver2.0(GUI Version) by DogBull (0) | 2006.07.23 |
Cyworld Today Counter Hack Ver1.0(Consol Version) by DogBull. (0) | 2006.07.23 |