티스토리 뷰

오목 서비스를 제공하기 위한 서버측 프로그램이다.
클라이언트 접속을 기다리고 접속이 발생할 경우 연결 쓰레드를 생성해 할당한다.
접속된 클라이언트를 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();
   }
}

댓글
Total
152,136
Today
21
Yesterday
31