마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

자바채팅서버에서 클라이언트로 String값 보내고 받는법

0 추천

안녕하세요. 안드로이드 독학한지 2주일정도 된 초보입니다.
우선 글이 길텐데 읽어주시면 감사하겠습니다.

 

현재 자바 채팅서버와 안드로이드 클라이언트를 구현한 상태입니다.
(자바이클립스로 서버를, 안드로이드스튜디오로 클라이언트를 구현함)

 

여기에 추가로 서버에서 1분마다 문제가 출력되고 정답을 맞추면
"사용자 님이 문제를 맞췄습니다"
라고 출력이 되는 채팅서버를 구현하는것이 목표입니다.

 

우선 자바 서버에 1분마다 문제가 출력되는 기능은 구현한 상태입니다.

그렇다면 정답 String 값을 구현해야 하는데 제가 해본방법은

 

String s1 = "자전거";
String s2 = "바람";

라고 선언을 하고(1번문제 정답은 자전거이고 2번문제정답은 바람이라고 가정했습니다)

클라이언트에서 입력한 데이터 "line" 과 s1 을 비교합니다

 

if(s1.equals(line))
{
System.out.println("사용자 님이 문제를 맞췄습니다");
s1 = s2;
}

 

클라이언트에서 입력한 데이터 line과 s1을 비교하여 같다면
문제를맞췄습니다 라고 출력을 한후
2번답으로 넘겨줍니다.

 

이방법을 사용할때 클라이언트가 한명일때는 정상적으로 잘됩니다.
하지만 클라이언트가 3명일때
유저1, 유저2, 유저3이 있을때

유저1이 자전거를 치면 유저1의 정답은 바람으로 넘어갑니다.
하지만 유저2, 유저3 의 정답까지 넘어가지않습니다..

 

유저1이 자전거를 쳐서 맞췄음에도 불구하고
유저2가 자전거를 입력하면 다시또 정답을 맞았다고합니다...

그러니까 유저1, 유저2, 유저3이 각각의 String 정답값을 가지고있는게
문제입니다.

 

유저1이 자전거를 입력할경우
정답처리를하고 유저1, 유저2, 유저3이 가지고있는
모든 String s1 값을 s2로 변경을 시켜주고싶습니다. <-핵심입니다.

 

자바채팅서버 보여드리겠습니다.


public class ChatServer {
  public static void main(String[] args) throws IOException
 {
  ServerSocket serverSoc = null;
  try
  {
   serverSoc = new ServerSocket(3333);
   System.out.println("서버가 시작되었습니다.");

   HashMap hm = new HashMap();
   while(true)
   {
    Socket sock = serverSoc.accept();
    ChatThread chatthread = new ChatThread(sock,hm);
    chatthread.start();
   }
  }
  catch (Exception ex)
  {
   System.out.println(ex);
  }
 }
}

class ChatThread extends Thread
{
 private Socket socket;
 private String id;

 private BufferedReader br;
 private PrintWriter pw;
 private HashMap hm;
 private boolean initFlag = false;
 public ChatThread(Socket socket, HashMap hm)
 {
  
  this.socket = socket;
  this.hm = hm;
  try
  {
   pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
   br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  
   id=br.readLine();
   
   System.out.println("사용자["+ id +"]님이 접속하셨습니다.");
   

   synchronized(hm)
   {
    hm.put(this.id,pw);
   }
   
   initFlag = true;
  }
  catch (Exception ex)
  {
   ex.printStackTrace();
  }
 }

 private String s1 = new String("자전거");
 private String s2= new String("바람"); 


 public void run()
 {
  try
  {
  
   String line = null;
   while((line = br.readLine()) != null)
   {
    broadcast(id + " : " +line);
    System.out.println(id + " : " +line);
    
    if(s1.equals(line)){
     System.out.println("사용자가 정답을 맞췄습니다.");
          s1 = s2;

 
    }
   }
   }
  catch (Exception ex)
  {
   ex.printStackTrace();
  }
  finally
  {
   synchronized(hm)
   {
    hm.remove(id);
    
   }
   try
   {
    if(socket!=null)
     socket.close(); 
   }
   catch (Exception ex)
   {
   }
  }

 }
 public void broadcast(String msg) throws IOException
 {
  synchronized(hm)
  {
   Collection col = hm.values();
   Iterator iter = col.iterator();
   while(iter.hasNext())
   {
    PrintWriter pw = (PrintWriter)iter.next();
    pw.println(msg);
    pw.flush();
   }
  }
 }

}

 

 자바소스를 보면 사실문제가있습니다.
서버에서 클라이언트가 접속한사람마다 각각의 String s1 = "자전거" 를 주기때문이죠


현재접속한 클라이언트 들에게 String s1을 던지는 방법을 알고싶습니다.
그리고 클라이언트중에 한명이라도 정답을 맞추면 s1을 String s2로 변경하는 방법이 필요합니다.


아니면 이방법이 아니더라도 다른좋은방법이 있거나 관련키워드가 있다면 알려주시면 감사하겠습니다.
전체소스를 보고 도움을 주실수있는분은 oht7202 카톡주시면 정말감사하겠습니다.

 

긴글읽어주셔서 감사합니다 댓글하나라도 달아주신다면 제가 구글검색
열심히해서 도움되도록하겠습니다.

싱송 (380 포인트) 님이 2015년 2월 11일 질문

1개의 답변

+1 추천
 
채택된 답변
보통 저런구조라면 클라이언트는 진짜답을 모르고 있고
답안지 제출시 서버에서 검토후 정답 여부만 알려주죠
서버에서는 현재 진행되고 있는 문제의 인덱스든 통정보든 들고 있고요
누가 답을 맞췄다면 클라이언트에게 답을 업데이트 하는것이 아니라
알림만 줘서 ui 업데이트만 시켜줘야죠
mamondebaltob (32,750 포인트) 님이 2015년 2월 11일 답변
싱송님이 2015년 2월 11일 채택됨
감사합니다만 도움이되질않습니다.. ㅠㅠ

보통 저런구조라면 클라이언트는 진짜답을 모르고 있고
(네 실제로 클라이언트는 문제나 답에관한정보는없습니다
문자를 보내는 부분만 있습니다)

답안지 제출시 서버에서 검토후 정답 여부만 알려주죠
(클라이언트가보낸메세지가 line 이고 정답 s1과
비교를하여 정답이맞다면) 요부분은 한상태입니다.
if(s1.equals(line))

서버에서는 현재 진행되고 있는 문제의 인덱스든 통정보든 들고 있고요
(네 제가소스에서 문제관련된부분은 내용이너무길어
글이안올라가서 지운상태이지만 타이머반복문으로
클라이언트에게 문제를 내는부분이 따로있습니다.)

누가 답을 맞췄다면 클라이언트에게 답을 업데이트 하는것이 아니라 알림만 줘서 ui 업데이트만 시켜줘야죠
(클라이언트에게 답을업데이트하진않고 알림만 줍니다

if(s1.equals(line)){
broadcast("*** ["+ id +"] 님이 정답을 맞췄습니다. 접답은 ["+ line +"] 입니다 ***");
}

말씀하신대로 잘되고있는데 문제는 이게아닙니다..

클라이언트가 접속할때마다 각각의 정답을 가지고있는게 문제이고 이를 해결하기위해 하나의 정답만 접속한클라이언트들에게
전달하고 정답처리를했을시 모든 1번정답을 2번정답으로 변경하는방법을 알고싶습니다
아 소스를 보니 새 사용자 접속했을때
새 스레드 만들어서 돌리시는데 문제와 정답이
스레드 종속적이니 말씀하신대로 될수밖에요
문제와 정답을 스레드 외부로 빼셔야합니다
네 답변감사합니다.
제가 스레드 외부에서 String s1 을 선언을 안해본건 아닙니다.
하지만 당연히 외부에서 선언된 String s1을 스레드내부에서
사용할수는 없었죠.. ㅠㅠ
외부에서 선언된 String s1을 내부에서 사용하는방법을
알고싶습니다 저위에 질문을 줄이면 요질문이 되겠네요.
답변감사합니다
가장 쉬운 해결책은 static 을 쓰면 되겠죠
다른 방법으로는 thread를 list 로 갖고 있다가 문제가 바뀌면
룹을 돌면서 각 thread에게 알려주는 방법이 있겠구요
좀 더 복잡한 방법으로는 db 를 사용하는 방법이 있겠네요
static!!! 해결했습니다.
사실 막연하게 자바 static 을 검색하다가
이를 응용하여 지식인에 질문을 하여 원하던 답을 찾아서
문제를해결하게됬습니다.
정말감사합니다. 덕분에 일주일동안 끙끙대던걸 해결하고 다음작업으로
넘어갈수있게됬습니다 정말정말감사합니다. 열심히 공부할게요!!!
...