Network – 소켓 프로그래밍 프로젝트

가톨릭대학교 컴퓨터네트워크 소켓 프로그래밍 프로젝트에서 발표한 자료 및 코드입니다.

프로젝트: CUK Chat Community
소개: 가톨릭대 학생들이 자유롭게 채팅할 수 있는 커뮤니티 (채팅 프로그램)
기능: 채팅 서버 접속, 메시지 전송, 채팅 인원 확인, 학교 주변 음식점 검색, 채팅 내용 삭제, 채팅 서버 나가기


프로그램 설계


1:N 채팅 설계


프로토콜


코드

1. Packet.java

import java.io.Serializable;

//패킷 클래스
public class Packet implements Serializable{
	private int cmd; // 명령어
	private String msg; // 메시지
	
	public Packet(int cmd, String msg) {
		this.cmd=cmd;
		this.msg=msg;
	}
	
	public int get_cmd() {
		return cmd;
	}
	
	public String get_msg() {
		return msg;
	}
}

2. server.java

import java.net.*;
import java.nio.charset.Charset;
import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.*;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;


//카카오 클래스 
class kakao{
	private String place_name;
	private String address_name;
	
	public kakao(String place_name, String address_name) {
		this.place_name=place_name;
		this.address_name=address_name;
	}
	
	public String get_place_name() {
		return place_name;
	}
	
	public String get_address_name() {
		return address_name;
	}
}

//음식점 찾기 클래스 
class findRestaurant{
 private static String keyword; // 키워드
 private static int size; // 검색 결과 수
 private static String GEOCODE_URL; // 검색 주소
 private static String GEOCODE_USER_INFO="KakaoAK 4eb81c3defb0830a786e6fd84f3e3f7c"; // 카카오 API에서 발급받은 Rest API Key
 
	public List<kakao> search(String keyword){
	    URL obj; // kakao api url
	    List<kakao> list=new ArrayList<kakao>(); // 리스트: ((음식점 이름, 음식점 주소),...)

	    try{
	        // Kakao API - 키워드로 지역 검색
	        keyword = URLEncoder.encode("역곡"+keyword, "UTF-8");
	        size=15;
	        GEOCODE_URL=String.format("http://dapi.kakao.com/v2/local/search/keyword.json?query=%s&size=%d",keyword,size);
	        System.out.println("검색 URL: "+GEOCODE_URL);

	        obj = new URL(GEOCODE_URL);
	        HttpURLConnection con = (HttpURLConnection)obj.openConnection();

	        con.setRequestMethod("GET");
	        con.setRequestProperty("Authorization",GEOCODE_USER_INFO);
	        con.setRequestProperty("content-type", "application/json");
	        con.setDoOutput(true);
	        con.setUseCaches(false);
	        con.setDefaultUseCaches(false);

	        Charset charset = Charset.forName("UTF-8");
	        BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream(), charset));

	        String inputLine;
	        StringBuffer response = new StringBuffer();

	        while ((inputLine = in.readLine()) != null) {
	            response.append(inputLine);
	        }
	        String jsonString=response.toString();
	        
	        // Json 문자열 파싱 -> List<kakao>에 저장
	        JSONParser jsonParser = new JSONParser();
	        JSONObject jsonObject = (JSONObject) jsonParser.parse(jsonString);
	        JSONArray jsonArray = (JSONArray) jsonObject.get("documents");
	        try {
	            for(int i=0; i<jsonArray.size(); i++){
	                JSONObject objectInArray = (JSONObject) jsonArray.get(i);
	                String place_name=(String) objectInArray.get("place_name");
	                String address_name=(String) objectInArray.get("address_name");
	                kakao k=new kakao(place_name,address_name);
	                list.add(k);
	            }
	        }
	        catch(Exception e){
	            e.printStackTrace();
	        }
	    }
	    catch(Exception e){
	        // TODO Auto-generated catch block
	        e.printStackTrace();
	    }
	    return list;
	    }
}

//수신 스레드
//클라이언트의 메시지를 받는 역할
class ServerReceiver extends Thread {
	  server s;
	  Socket socket;
	  ServerSender server_sender;
	  ObjectInputStream in;
	  ObjectOutputStream out;
	  
	 // (접속한 클라이언트와 수신하는) 스레드 객체의 멤버 초기화 
	  ServerReceiver(server s, Socket socket, ServerSender server_sender) {
		  this.s=s;
		  this.socket = socket;
		  this.server_sender=server_sender;
		  try {
			  in = new ObjectInputStream(socket.getInputStream()); // 데이터 수신을 편하게 하도록 도와주는 객체 (접속한 클라이언트 -> 서버)
			  out = new ObjectOutputStream(socket.getOutputStream()); // 데이터 송신을 편하게 하도록 도와주는 객체 (서버 -> 접속한 클라이언트) 
		  } 
		  catch(IOException e) {}
	  }
	  
	  @Override
	  public void run() {
		  String name = "";
		  String code = "";
		  String client_key = "";
		  try {
			  // 처음 클라이언트가 접속한 상황 -> 대기하다가 수신된 클라이언트 이름을 받아서 clients에 저장, 현재 클라이언트 수 출력 
			  Packet packet = (Packet)in.readObject(); 
			  
			  // 클라이언트 이름 및 학번 확인
			  name = packet.get_msg();
			  name = name.substring(0,name.length()-9);
			  code = packet.get_msg();
			  code = code.substring(code.length()-9,code.length()-5);
			  
			  // 클라이언트 이름(학번 일부), 데이터 송신 관련 객체를 저장 
			  client_key=name+"("+code+")";
			  s.clients.put(client_key, out);
			  
			  // 클라이언트 입장 
			  System.out.println("#"+name+"님이 입장하셨습니다.");
			  server_sender.sendMemberToClient(client_key); // 접속한 클라이언트에게 온라인 멤버 리스트 보내주기
			  server_sender.sendToAllFirst(client_key,"#"+name+"님이 입장하셨습니다.");
			  System.out.println("현재 서버접속자 수는 " + s.clients.size() + "입니다.");

			  
			  // 이후에는 다음을 반복 (수신 대기하다 메시지 받으면 저장 -> 모든 클라이언트에게 메시지 송신)
			  while(in!=null) {
				  // 패킷 얻으면 분석 
				  packet = (Packet)in.readObject(); 
				  int cmd=packet.get_cmd();
				  String msg=packet.get_msg();
				  System.out.println(msg);
				  
				  // 멤버 리스트 요청
				  if(cmd==0x40) {
					  server_sender.sendMemberToClient(client_key);
				  }
				  // 음식점 검색
				  else if(cmd==0x30) {
					  	msg=msg.substring(1,msg.length());
					  	server_sender.sendRestaurantToClient(client_key,msg);
				  }
				  // 메시지 전송
				  else {
					  server_sender.sendToAll(msg);  
				  }
			  }
		  }
		  catch(Exception e) {
			  System.out.println("예외 메시지:"+e.getMessage());
		  }
		  // try문이 종료되면 다음을 실행 
		  // ex) 클라이언트가 나가서 in객체가 제대로 동작을 안 함
		  // 0x10
		  finally {
			  server_sender.sendToAll("#"+name+"님이 퇴장하셨습니다.");
			  s.clients.remove(client_key);
			  System.out.println("["+socket.getInetAddress()+":"+socket.getPort()+"]"+"에서 접속을 종료하였습니다.");
			  System.out.println("현재 서버접속자 수는 "+ s.clients.size()+"입니다.");
		  } 
	  } 
}

//송신 클래스 (스레드 x)
//클라이언트에게 메시지를 보내는 역할
class ServerSender{
	server s;
	
	 public ServerSender(server s) {
		 this.s=s;
	 }
	
	 // 특정 클라이언트에게 송신(멤버 리스트) : 0x40
	 void sendMemberToClient(String client_key) {
		 String members=""; 
		 Iterator it = s.clients.keySet().iterator();
		 while(it.hasNext()) {
			 members=members.concat(it.next()+"\n");
		 }
		 try {
			 ObjectOutputStream out = (ObjectOutputStream)s.clients.get(client_key);
			 out.writeObject(new Packet(0x40,members));
		 }
		 catch(Exception e){
			  System.out.println("예외 메시지:"+e.getMessage());
		 }
	 }
	 
	 // 특정 클라이언트에게 송신(음식점 검색) : 0x30
	 void sendRestaurantToClient(String client_key, String msg) {
		 String rsts="[음식점 검색] "+msg+'\n'; // 특수기호로 멤버를 보내는 메시지 구분 
		 List<kakao> list=s.rst.search(msg);
		 for(int i=0; i<list.size(); i++) {
			 if(i<10)
				 rsts=rsts.concat((i+1)+". "+list.get(i).get_place_name()+"("+list.get(i).get_address_name()+")"+"\n");
		 }
		 System.out.println(rsts);
		 try {
			 ObjectOutputStream out = (ObjectOutputStream)s.clients.get(client_key);
			 out.writeObject(new Packet(0x30,rsts));
		 }
		 catch(Exception e){
			  System.out.println("예외 메시지:"+e.getMessage());
		 }
	 }
	 
	 // (처음 통신) 모든 클라이언트에게 메시지 송신 : 0x20
	 void sendToAllFirst(String client_key, String msg) {
		 Iterator it = s.clients.keySet().iterator();
		 
		 // clients에 저장된 key값이 있으면 반복 
		 while(it.hasNext()) {
			 try {
				 String crt_client_key=(String) it.next();
				 System.out.println(crt_client_key);
				 System.out.println(client_key);
				 
				 // 처음 통신을 시도한 클라이언트 
				 if(crt_client_key.equals(client_key)) {
					 ObjectOutputStream out = (ObjectOutputStream)s.clients.get(client_key);
					 out.writeObject(new Packet(0x20,msg)); 
				 }
				 else {
					 ObjectOutputStream out = (ObjectOutputStream)s.clients.get(crt_client_key);
					 out.writeObject(new Packet(0x21,msg)); 
				 }
			 }
			 catch(Exception e){
				  System.out.println("예외 메시지:"+e.getMessage());
			 }
		 } 
	 }
	 
	 // 모든 클라이언트에게 메시지 송신 : 0x21
	 void sendToAll(String msg) {
		 Iterator it = s.clients.keySet().iterator();
		 
		 // clients에 저장된 key값이 있으면 반복 
		 while(it.hasNext()) {
			 try {
				 // 현재 클라이언트와 송신하기 위해서 out 객체 가져오기
				 ObjectOutputStream out = (ObjectOutputStream)s.clients.get(it.next());
				 // 현재 클라이언트에게 송신 
				 out.writeObject(new Packet(0x21,msg));
			 }
			 catch(Exception e){
				  System.out.println("예외 메시지:"+e.getMessage());
			 }
		 } 
	 }
}

public class server {
	// 접속한 클라이언트 목록  
	ConcurrentHashMap clients;
	// 음식점 검색 객체
	findRestaurant rst;
	 
	// key:클라이언트 이름+아이피, value:데이터 송신 관련 객체 (서버 -> 클라이언트)  
	 public server(findRestaurant rst) {
	  clients = new ConcurrentHashMap();
	  this.rst=rst;
	 }

	
	// 서버 오픈
	 public void start() {
		 ServerSocket serverSocket = null;
		 Socket socket = null;
	
		 try {
			 // 서버 컴퓨터의 7777 포트에서 채팅 프로그램 동작 
			 serverSocket = new ServerSocket(7777);
			 System.out.println("서버가 시작되었습니다.");
			 
			 // 서버의 송신 객체 생성
			 ServerSender server_sender=new ServerSender(this);
			 
			 // 반복 (접속할 클라이언트 대기 -> 접속한 클라이언트에 대한 수신 스레드 생성) 
			 while(true) {
				 // 대기하다가 연결된 클라이언트가 있으면 해당 클라이언트에 대한 소켓을 생성함
				 socket = serverSocket.accept(); 
				 System.out.println("["+socket.getInetAddress() + ":"+socket.getPort()+"]"+"에서 접속하였습니다.");
				 // 해당 클라이언트의 메시지를 수신하는 스레드 생성 
				 ServerReceiver thread = new ServerReceiver(this,socket,server_sender);
				 // 스레드 동작 
				 thread.start();
			 }
		 }
		 catch(Exception e) {
			  System.out.println("예외 메시지:"+e.getMessage());
		 }
	 } 
	  

	 public static void main(String args[]) {
		 // 음식점 검색 객체 생성
		 findRestaurant rst=new findRestaurant();
		 // 서버 객체 생성
		 server s = new server(rst);
		 // 서버 오픈
		 s.start();
	 }  
} 

3. client.java

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.text.DefaultCaret;

import java.net.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.Color;
import java.io.*;
import java.util.Scanner;

//수신 클래스 
//서버의 메시지를 받는 역할 <스레드>
class ClientReceiver extends Thread{
	  Socket socket;
	  ObjectInputStream in;
	  ClientGUI gui;
	  
	  // (서버와 수신하는) 스레드 객체의 멤버 초기화 
	  ClientReceiver(ClientGUI gui, Socket socket) {
		  this.gui=gui;
		  this.socket = socket;
		  try {
		    in = new ObjectInputStream(socket.getInputStream());  // 데이터 수신을 편하게 하도록 도와주는 객체 (서버 -> 클라이언트)
		  } 
		  catch(Exception e) {
			  System.out.println("예외 메시지:"+e.getMessage());
		  }
	  }
	  
	  @Override
	  public void run() {
		  // 반복 (수신 대기하다가 메시지 받으면 저장 -> TextArea에 출력) 
		  while(in!=null) {
			  try {
				  Packet packet = (Packet)in.readObject();
			      String msg=packet.get_msg();

			     // 멤버 리스트
			     if(packet.get_cmd()==0x40) {
			    	 gui.txtarea2.append(msg);
			    	 gui.stt_field.setText("0x40");
			     }
			     // 처음 온 메시지
			     else if(packet.get_cmd()==0x20) {
			    	 gui.txtarea.append(msg+'\n');
			    	 gui.stt_field.setText("0x20");
			     }
			     // 메시지  
			     else if(packet.get_cmd()==0x21) {
			    	 gui.txtarea.append(msg+'\n');
			    	 gui.stt_field.setText("0x21");
			     }
			     // 음식점
			     else if(packet.get_cmd()==0x30){
			    	 gui.txtarea.append(msg+'\n');
			    	 gui.stt_field.setText("0x30");
			     }
			   }
			  catch(Exception e) {
				  System.out.println("예외 메시지:"+e.getMessage());
			  }
		  }
	  } 
}

//송신 클래스 
//서버에게 메시지를 보내는 역할 
/*
 * 0x10: 종료
 * 0x20: 처음 통신
 * 0x21: 통신
 * 0x30: 검색
 * 0x40: 인원 확인 
 * */
class ClientSender{
	 Socket socket;
	 ObjectOutputStream out;
	 String name;
	 String code;
	 ClientGUI gui;
	 
	  // 송신 준비 
	  ClientSender(ClientGUI gui, Socket socket, String name, String code) {
		  this.gui=gui;
		  this.socket = socket;
		  try {
		   this.out = new ObjectOutputStream(socket.getOutputStream()); // 데이터 송신을 편하게 하도록 도와주는 객체 (클라이언트 -> 서버) 
		   this.name = name;
		   this.code=code;
		  } 
		  catch(Exception e) {
			  System.out.println("예외 메시지:"+e.getMessage());
		  }
	  }
	  
	  // 처음에는 서버에 이름과 학번 전송
	  public void first() {
		  try {
			   Packet packet=new Packet(0x20,name.concat(code));
			   out.writeObject(packet);
		  }
		  catch(IOException e) {
			  System.out.println("예외 메시지:"+e.getMessage());
		  }
	  } 
	  
	  // 음식점 검색, 메시지 전송 
	  public void msg_send(String msg) {
		  try {
			  	// 음식점 검색
			  	if(msg.charAt(0)=='!')
			  		out.writeObject(new Packet(0x30,msg));
			  	// 메시지 전송 
			  	else
			  		out.writeObject(new Packet(0x21, "["+name+"] "+msg));
		  }
		  catch(IOException e) {
			  System.out.println("예외 메시지:"+e.getMessage());
		  }
	  } 
	  
	  // 멤버 리스트 요청
	  public void request_member() {
		  try {
			  out.writeObject(new Packet(0x40,""));
		  }
		  catch(IOException e) {
			  System.out.println("예외 메시지:"+e.getMessage());
		  }
	  }
}


// 버튼 이벤트 처리
// (서버 연결, 메시지 전송, 인원 수 확인) 
class Action implements ActionListener{
	ClientGUI gui;
	ClientSender sender;
	Thread receiver;
	
	// 생성자
	public Action(ClientGUI gui) {
		this.gui=gui;
		
		// 키 이벤트 생성 <Connect, Send>
		// <Connect>
		gui.name_field.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				if(e.getKeyCode()==e.VK_ENTER) {
					connect_func(); // 서버 연결 
					gui.msg_field.requestFocusInWindow(); // 커서 위치 변경
				}
			}
		});
		// <Send>
		gui.msg_field.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				if(e.getKeyCode()==e.VK_ENTER) {
					send_func(); // 메시지 전송
				}
			}
		});
	}
	
	// 학생 검사
	/*
	 * 1. 학번에는 숫자만 포함돼있음 
	 * 2. 학번의 자릿수는 9자리
	 * 3. 학번의 앞 네 자리는 1855~2022 사이 
	 */
	boolean check_code(String code) {
		try {
			int code_int=Integer.parseInt(code);
			int four=Integer.parseInt(code.substring(0,4));
			if(code.length()==9 && four>=1855 && four<=2022)
				return true;
			else
				return false;
		}
		catch(NumberFormatException e) {
			return false;
		}
	}
	
	// 서버 연결 
	public void connect_func() {
	    	// TextArea 초기화
	    	gui.txtarea.setText(null);
	    	gui.txtarea2.setText(null);
	    	
	    	String ip="(서버 외부 IP 주소)";
	    	String port="7777";
	    	
	    	// 컴포넌트 값 가져오기 
	    	String code=gui.code_field.getText();
	    	String name= gui.name_field.getText();
	    	
	    	// 올바른 학번인지 검사
	    	boolean student=check_code(code);
	    	
	    	// 학생이 확인되고 닉네임이 존재하면 서버에 연결
	    	if(student && !name.equals("")) {
	    		try {
	  			    // port 정수화
	  			    int port_int=Integer.parseInt(port);
	  			  
	  			  	// 소켓 생성 
	  			  	Socket socket = new Socket(ip, port_int); 
	        		
					// 서버와 송신하는 객체 생성
					sender = new ClientSender(gui,socket, name, code);
					sender.first();
					
					// 서버와 수신하는 객체 생성 
					receiver = new Thread(new ClientReceiver(gui,socket));
					receiver.start();
					
					// 접속 버튼 비활성화
					gui.cnxt_btn.setEnabled(false);
	  		  }
			  catch(ConnectException err) {
				  // 서버에 접속 실패 
				  gui.txtarea.append("서버와 연결을 실패했습니다.");
				  err.printStackTrace();
			  }
	  		  catch(Exception err) {
				  // 서버에 접속 실패 
				  gui.txtarea.append("서버와 연결을 실패했습니다.");
				  err.printStackTrace();
	  		  }	
	    	}
	    	
	    	// 학생이 아님
	    	else {
				  gui.txtarea.append("올바르지 않은 학번이거나, 닉네임과 학번이 입력되지 않았습니다.");
	    	}
	}
	
	// 전송
	public void send_func() {
    	// 컴포넌트 값 가져오기 
    	String msg=gui.msg_field.getText();
    	
    	// msg가 채워져 있으면 실행 
    	if(!msg.equals("")) {
    		// 메시지 전송
    		try {
        		sender.msg_send(msg);
    		}
    		catch(Exception err){}
    		
    		// 메시지필드 초기화
    		gui.msg_field.setText(null);	
    	}
	}
	
	// 버튼이 눌린 경우 처리 
	@Override
	public void actionPerformed(ActionEvent e) {
		 JButton act=(JButton) e.getSource(); //활동하는 버튼 
	     String actname=act.getText(); // 활동하는 버튼의 텍스트
	            
	        switch(actname) {
	            case "Connect":
	            	connect_func();
	                break;
	                
	            case "Send":
	            	send_func();
	                break;
	           
	            case "Clear Chat":
	            	// TextArea 초기화
	            	gui.txtarea.setText(null);
	                break;
	                
	            case "Refresh":
	            	gui.txtarea2.setText(null);
	            	sender.request_member();
	                break;
	            
	        }
	}
	
}

class ClientGUI extends JFrame{
	// 컴포넌트 선언 
	JLabel code_label;
	JTextField code_field;
	JLabel name_label;
	JTextField name_field;
	JLabel chat_label;
	JButton clear_btn;
	JLabel stt_label;
	JTextField stt_field;
	JTextArea txtarea;
	JScrollPane txtareaplus;
	JLabel msg_label;
	JTextField msg_field;
	JButton cnxt_btn;
	JLabel user_label;
	JButton refresh_btn;
	JTextArea txtarea2;
	JScrollPane txtareaplus2;
	JButton send_btn;
	
	public ClientGUI() {
		// GUI 기본 세팅 
		setSize(670,420);
        setLocation(700,300);
		setTitle("CUK Chat Community");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		/*
		 * 채팅 앱 디자인
		 */
		
		// contentPane 정의 
		JPanel contentPane = new JPanel();
		setContentPane(contentPane);
		contentPane.setLayout(null);
		
		// 패널 정의 
		JPanel panel_0 = new JPanel();
		panel_0.setBounds(0, 0, 470, 400);
		panel_0.setLayout(null);
		add(panel_0);
		
		JPanel panel_1 = new JPanel();
		panel_1.setBounds(470, 0, 200, 400);
		panel_1.setLayout(null);
		add(panel_1);
		
		
		// 패널 0 디자인
		
		// 패널 0 - 1행 		
		code_label=new JLabel("Code:");
		code_label.setBounds(10,10,80,25);
		panel_0.add(code_label);
		
		code_field=new JTextField();
		code_field.setBounds(60,10,160,25);
		panel_0.add(code_field);
		
		name_label=new JLabel("Name:");
		name_label.setBounds(240,10,80,25);
		panel_0.add(name_label);
		
		name_field=new JTextField();
		name_field.setBounds(300,10,160,25);
		name_field.setText(null);
		panel_0.add(name_field);

		// 패널 0 - 2행 
		chat_label=new JLabel("Chat:");
		chat_label.setBounds(10,45,80,25);
		panel_0.add(chat_label);
		
		clear_btn=new JButton("Clear Chat");
		clear_btn.setBounds(60,45,160,25);
		panel_0.add(clear_btn);
		
		stt_label=new JLabel("Status:");
		stt_label.setBounds(240,45,80,25);
		panel_0.add(stt_label);
		
		stt_field=new JTextField();
		stt_field.setBounds(300,45,160,25);
		stt_field.setForeground(new Color(0,0,255));
		stt_field.setText("None");
		panel_0.add(stt_field);
		
		// 패널 0 - 3행 
		txtarea = new JTextArea();
		DefaultCaret caret = (DefaultCaret)txtarea.getCaret(); // auto-scroll 
		caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
		txtareaplus = new JScrollPane(txtarea);
		txtarea.setEditable(false);
		txtareaplus.setBounds(10,80,450,260);
		panel_0.add(txtareaplus);
		
		// 패널 0 - 4행 
		msg_label=new JLabel("Msg:");
		msg_label.setBounds(10,350,80,25);
		panel_0.add(msg_label);
		
		msg_field=new JTextField();
		msg_field.setBounds(60,350,400,25);
		panel_0.add(msg_field);
		
		
		// 패널 1 디자인
		
		// 패널 1 - 1행
		cnxt_btn=new JButton("Connect");
		cnxt_btn.setBounds(0,10,175,25);
		panel_1.add(cnxt_btn);
		
		// 패널 1 - 2행 
		user_label=new JLabel("Users:");
		user_label.setBounds(0,45,80,25);
		panel_1.add(user_label);
		
		refresh_btn=new JButton("Refresh");
		refresh_btn.setBounds(50,45,125,25);
		panel_1.add(refresh_btn);
		
		// 패널 1 - 3행 
		txtarea2 = new JTextArea();
		DefaultCaret caret2 = (DefaultCaret)txtarea2.getCaret(); // auto-scroll 
		caret2.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
		txtareaplus2 = new JScrollPane(txtarea2);
		txtarea2.setEditable(false);
		txtareaplus2.setBounds(0,80,175,260);
		panel_1.add(txtareaplus2);
		
		// 패널 1 - 4행 
		send_btn=new JButton("Send");
		send_btn.setBounds(0,350,175,25);
		panel_1.add(send_btn);
		
		
		// 버튼 이벤트 처리
		Action action=new Action(this);
		clear_btn.addActionListener(action);
		cnxt_btn.addActionListener(action);
		refresh_btn.addActionListener(action);
		send_btn.addActionListener(action);
		
		// 시각화 
        setVisible(true);
	}
}

public class client{
	
	public static void main(String[] args) {
		ClientGUI gui=new ClientGUI();
	}

}


발표 자료

Leave a Reply

Your email address will not be published. Required fields are marked *