-
728x90
웹소켓을 활용한 채팅
jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String contextPath = request.getContextPath(); int port = request.getLocalPort(); String serverName = request.getServerName(); %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Chat Client Socket</title> </head> <body> <h1>웹소켓을 활용한 챗팅</h1> <p>사용자 아이디를 입력 하고 로그인 하면 체팅이 시작 됩니다!</p> <form> 사용자 : <input id="sender" type="text" value="user1"> <input id="loginBtn" value="Login" type="button"> <input id="closeBtn" value="Disconnect" type="button"><br> 받는이: <select id="recipient"> <option value="All">All</option> </select><br> 메세지: <input id="txtMsg" type="text" value="hello"> <input id="sendBtn" value="Send" type="button"> </form> <hr> <textarea id="msgTxtArea" rows="10" cols="50"></textarea> <script> // 웹소켓 프로토콜을 이용해서 서버와 연결 // WebSocket은 HTML5에 기본 제공된다. var socket =null; var txt=document.getElementById("msgTxtArea"); function connection(){ socket.onopen = function(message) { console.log("onpen ..."); txt.value+=(">>>open...\n"); } socket.onclose = function(message) { txt.value+=(">>>onclose...\n"); console.log("onclose ..."); } socket.onerror = function(err) { txt.value+=(">>>error...\n"); console.log("소켓 오류", err); } socket.onmessage = function(message) { try{ //var html=""; var html="<option value= All> All</option>"; var userList=JSON.parse(message.data); console.log(userList); for(var i in userList){ var user=userList[i]; html += "<option value=" + user + ">"+ user + "</option>"; } document.getElementById("recipient").innerHTML=html; }catch(e){ txt.value+=(message.data+"\n"); } } } loginBtn.onclick=function(){ var sender=document.getElementById("sender").value; socket=new WebSocket("ws://<%=serverName%>:<%=port%>/<%=contextPath%>/broadSocket/"+sender); connection(); } sendBtn.onclick=function(){ var msg=document.getElementById("txtMsg").value; var recip=document.getElementById("recipient").value; txt.value+=("나: "+msg+"\n"); socket.send(recip+"|\|"+msg); } closeBtn.onclick=function(){ socket.close(); } </script> </body> </html>
소켓 java
import java.io.IOException; import java.io.PrintWriter; import java.security.cert.Extension; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import javax.websocket.Extension.Parameter; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.RemoteEndpoint.Basic; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; @ServerEndpoint(value="/broadSocket/{userID}") public class BroadSocket3 implements Runnable { // 귓속말 메세지를 전달 할 session을 userID로 찾기 위해서 userID와 session을 맵핑한다. static Map<String, Session> sessionMap = Collections.synchronizedMap(new HashMap<>()); static int mapSize; static boolean sentFlag = false; static String closeUserID = ""; public BroadSocket3() { mapSize = sessionMap.size(); new Thread(this).start();; } @OnOpen public void onOpen(Session session, @PathParam("userID") String userID) throws IOException { //System.out.println("소켓 서버 "+ session.getId() +"이(가) 오픈 되었습니다..."); //System.out.println(Arrays.toString(session.getClass().getFields()) ); //System.out.println("session id : " + session.getId()); // 쿼리 스트링을 받을 수 있다. //System.out.println("session querystr : " + session.getQueryString()); // 문자열 리스트를 파라미터 맵으로 전달 받을 수 있다. //Map<String, List<String>> params = session.getRequestParameterMap(); //System.out.println(params.get("sender")); // PathParam 어노테이션을 이용한 파라미터 전달 //System.out.println("path param sender : " + userID); // 접속한 사용자의 session을 Map에 저장한다. if(!sessionMap.containsKey(userID)&&!userID.equals("All")) { sessionMap.put(userID, session); synchronized(sessionMap) { for(String userid : sessionMap.keySet()) { Session sess = sessionMap.get(userid); Set<String> keyset = sessionMap.keySet(); Iterator<String> iter = keyset.iterator(); StringBuffer strbf = new StringBuffer("["); while(iter.hasNext()) { strbf.append("\""+iter.next()+"\","); } strbf.deleteCharAt(strbf.lastIndexOf(",")); strbf.append("]"); sess.getBasicRemote().sendText(strbf.toString()); } mapSize = sessionMap.size(); } for(String userid : sessionMap.keySet()) { (sessionMap.get(userid)).getBasicRemote().sendText(userID + "||님이 입장하였습니다!"); } }else { session.getBasicRemote().sendText("등록된 id입니다."); } //sessionMap.put(userID, session); } @OnClose public void onClose(Session session, @PathParam("userID") String userID) throws IOException { System.out.println("소켓 서버"+ session.getId() +"이(가) 닫혔습니다..."); sessionMap.remove(userID); closeUserID = userID; } @OnMessage public void onMessage(String message, Session session, @PathParam("userID") String userID) throws IOException { System.out.println("받은 메세지 : " + message); // clientSessionSet에서 클라이언트 세션을 가져와서 sender를 제외한 모든 세션에 메세지를 보낸다. // 동기적으로 메세지를 보내야 한다. synchronized(sessionMap) { //System.out.println("set size : " + sessionMap.size()); System.out.println(message); StringTokenizer stk = new StringTokenizer(message, "||"); String recipient = stk.nextToken().trim(); String msg = stk.nextToken().trim(); if("All".equals(recipient)) { for(String userid : sessionMap.keySet()) { if(!userid.equals(userID)) { //https://docs.oracle.com/javaee/7/api/javax/websocket/Session.html#getBasicRemote-- // 클라이언트 session에서 RemoteEndpoint 객체를 받아와서 메세지 텍스트를 보낸다. // RemoteEndpoint를 통해서 동기적으로 메세지를 보낼 수 있다. (sessionMap.get(userid)).getBasicRemote().sendText(userID + " : " + msg); } } } else { (sessionMap.get(recipient)).getBasicRemote().sendText(userID + " : " + msg); } } } @OnError public void onError(Throwable th) { th.printStackTrace(); } @Override public void run() { while(true){ try { Thread.sleep(1000); if(mapSize != sessionMap.size()) { synchronized(sessionMap) { for(String userid : sessionMap.keySet()) { Session session = sessionMap.get(userid); Set<String> keyset = sessionMap.keySet(); Iterator<String> iter = keyset.iterator(); StringBuffer strbf = new StringBuffer("["); while(iter.hasNext()) { strbf.append("\""+iter.next()+"\","); } strbf.deleteCharAt(strbf.lastIndexOf(",")); strbf.append("]"); session.getBasicRemote().sendText(strbf.toString()); if(mapSize > sessionMap.size()) { session.getBasicRemote().sendText(closeUserID+"님이 퇴장 하였습니다!"); } } } mapSize = sessionMap.size(); } } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } }
728x90반응형'공부' 카테고리의 다른 글
마크다운 (0) 2023.07.23 HTML 이클립스 설정 (0) 2022.08.29 H2 auto_increment 추가 (0) 2022.08.24 서블릿 (0) 2022.08.16 데이터베이스 (0) 2022.08.10