이안의 평일코딩

JAVA의 정석 35일차 - 자바 마지막 예제 본문

Back-end/Java

JAVA의 정석 35일차 - 자바 마지막 예제

이안92 2020. 7. 31. 10:57
반응형

2020.07.31(금)

1. Client, Server => 공통으로 사용되는 클래스

 프로그램의 기능 설정 => 내부 프로토콜 (서버와 클라이언트의 약속)

 Client - Server 접속

 Socket s = new Socket("",PORT) => 서버주소

         ==

     서버 정보

                      

 클라이언트 정보를 확인

 클라이언트 IP, PORT ===합쳐서==> Socket

 => Socket s = ss.accept();

              ==

       클라이언트 정보

 

 Client 접속 Server => 저장장소 (Vector)에 클라이언트 IP, PORT

 통신 클라이언트 => 요청, 서버 => 요청처리

 

 웹 서버 => 

 

Function

package com.sist.common;

public class Function {
	// 로그인 처리 => 이미 로그인 된 사람
	public static final int LOGIN=100;
	public static final int MYLOG=110;
	
	// 방만들기
	// 방들어가기
	// 방나가기
	// 대기실 수정
	
	// 대기실 채팅
	public static final int WAITCHAT=500;
	// 방채팅
	
	// 쪽지보내기
	// 채팅 종료
	// 1:1 게임
	
}

 

Server

package com.sist.server;
// network => net => 라이브러리(import로 가져옴)
import java.util.*;

import com.sist.common.Function;

import java.io.*; // 입출력 (서버와 클라이언트의 데이터 주고 받기)
import java.net.*; // 다른 컴퓨터와 연결
/*
 *  일반 서버 (Application) => Socket(연결 기계 => 소프트웨어로 제작)
 *  웹서버 => URL
 *  ========================================연결지향적 프로그램 TCP
 *    TCP 
 */
// Server => 접속만 담당 => 저장
// Client => 실제 통신 담당 => 클라이언트마다 따로 통신= > 쓰레드 이용
public class Server implements Runnable{
	private ServerSocket ss; // 접속을 받는 클래스 => 정보 저장
	private final int PORT = 9875;
	// 클라이언트 접속시에 정보 저장(IP, PORT)
	private Vector<Client> waitVc = new Vector<Client>();
	// 쓰레드에서 동기화 프로그램
	
	// 서버 가동
	public Server() {
		try {
			ss = new ServerSocket(PORT);
			/*
			 * bind() => IP, PORT 묶어주는 역할
			 *   ===> 핸드폰 (개통)
			 * listen() => 대기상태 (클라이언트가 접속하기 전까지 대기)
			 */
			System.out.println("Server Start...");
		}catch(Exception ex) {}
	}
	// 클라이언트가 접속을 했을 경우 => 각자 통신이 가능하게 쓰레드와 연결
	@Override
	public void run() {
		try {
			while(true) {
				Socket s = ss.accept();
				// accept() : 특수한 메소드 => 클라이언트가 접속시에만 호출되는 메소드
				Client client = new Client(s);
				client.start(); // 클라이언트와 통신 승인
			}
		}catch(Exception ex) {}
		
	}
	
	public static void main(String[] args) {
		// 서버 가동
		Server server = new Server();
		new Thread(server).start();
		// Server클래스에 있는 run()을 호출
	}
	// 내부 클래스 => Server가 가지고 있는 데이터 쉽게 공유가 가능하게 만든다
	class Client extends Thread{
		Socket s; // 클라이언트와 연결
		BufferedReader in; // 클라이언트로부터 요청을 받는다
		OutputStream out; // 요청을 처리한 다음에 결과를 응답
		String id,name,sex,pos; // 변수 설정
		public Client(Socket s) {
			try {
				this.s = s;
				in = new BufferedReader(new InputStreamReader(s.getInputStream()));
				// 클라이언트 요청한 메소드를 읽어오는 메모리 공간
				out = s.getOutputStream();
			}catch(Exception ex) {}
		}
		// 통신 ? => 기능(요청 처리)
		public void run() {
			try {
				while(true) {
					// 클라이언트가 요청한 내용을 받는다
					String msg = in.readLine();
					StringTokenizer st = new StringTokenizer(msg,"|");
					int protocol = Integer.parseInt(st.nextToken());
					// 100|id|대화명|성별
					switch(protocol) {
					case Function.LOGIN:{
						// 로그인 처리
						// 데이터값 받기
						id = st.nextToken();
						name = st.nextToken();
						sex = st.nextToken();
						pos = "대기실"; // 사용자의 기본 정보
						
						// 접속한 모든 사용자 => 로그인한 정보를 보내준다
						this.messageAll(Function.LOGIN+"|"+id+"|"+name+"|"+sex+"|"+pos);
						// 접속한 사람의 정보를 저장
						waitVc.add(this);
						// Client client = new Client();
						messageTo(Function.MYLOG+"|"+id);
						// 로그인창에서 => 대기실창으로 변경
						for(Client user:waitVc) {
							messageTo(Function.LOGIN+"|"+user.id+"|"+user.name+"|"+user.sex+"|"+user.pos);
						}
						// 입장메세지 출력
						messageAll(Function.WAITCHAT+"|{☞"+name+"님이 입장하셨습니다]");
						// 개설된 방정보 전송
						
					}
					break;	
					case Function.WAITCHAT:{
						messageAll(Function.WAITCHAT+"|["+name+"]"+st.nextToken());
					}
					break;
					}
				}
			}catch(Exception ex) {}
		}
		// 응답 처리
		// 개인적으로 전송
		public synchronized void messageTo(String msg) {
			// synchronized
			/*
			 * 쓰레드는 default : 비동기화
			 * synchronized => 동기화
			 */
			try {
				out.write((msg+"\n").getBytes());
				//인코딩 ==> 디코딩
			}catch(Exception ex) {}
		}
		// 전체적으로 응답
		public synchronized void messageAll(String msg) {
			try {
				for(Client user:waitVc) {
					user.messageTo(msg);
				}
			}catch(Exception ex) {}
		}
	}
	
}

 

WaitRoom

package com.sist.client;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class WaitRoom extends JPanel{
	JTable table1, table2;
	DefaultTableModel model1, model2;
	JTextField tf;
	JTextArea ta;
	JButton b1, b2, b3, b4, b5, b6;
	JScrollBar bar;
	
	public WaitRoom() {
		String[] col1 = {"방이름", "공개/비공개", "인원"};
		String[][] row1 = new String[0][3];
		
		model1 = new DefaultTableModel(row1, col1);
		table1 = new JTable(model1);
		JScrollPane js1 = new JScrollPane(table1);
		
		String[] col2 = {"ID", "대화명", "성별", "위치"};
		String[][] row2 = new String[0][3];
		
		model2 = new DefaultTableModel(row2, col2);
		table2 = new JTable(model2);
		JScrollPane js2 = new JScrollPane(table2);
		
		ta = new JTextArea();
		ta.setEditable(false);
		JScrollPane js3 = new JScrollPane(ta);
		bar = js3.getVerticalScrollBar();
		
		tf = new JTextField();
		
		b1 = new JButton("방만들기");
		b2 = new JButton("방들어가기");
		b3 = new JButton("정보보기");
		b4 = new JButton("쪽지보내기");
		b5 = new JButton("일대일게임");
		b6 = new JButton("나가기");
		
		// 배치
		setLayout(null);
		js1.setBounds(10, 15, 600, 500);
		js2.setBounds(10, 520, 600, 350);
		add(js1);
		add(js2);
		
		js3.setBounds(615, 15, 390, 465);
		add(js3);
		tf.setBounds(615, 485, 390, 30);
		add(tf);
		
		JPanel p = new JPanel();
		p.setLayout(new GridLayout(3,2,5,5));
		p.add(b1); p.add(b2);
		p.add(b3); p.add(b4);
		p.add(b5); p.add(b6);
		
		p.setBounds(615, 520, 390, 350);
		add(p);
	}
}

 

login

package com.sist.client;
import javax.swing.*;
import java.awt.*;
/*
 *    class JPanel extends Object
 *    class Login extends JPanel
 */
public class Login extends JPanel{
   // 스킨 
   private Image back;
   private JLabel la1,la2,la3;
   // Login
   JTextField tf;
   JTextField pf;
   JButton b1,b2;
   JRadioButton rb1, rb2;
   // MainForm 
   public Login() 
   {
	   
	   // 이미지 정보 읽기
	   back=Toolkit.getDefaultToolkit().getImage("c:\\javaDev\\back.jpg");
	   
	   setLayout(null);// 직접배치
	   la1=new JLabel("아이디",JLabel.RIGHT);
	   la1.setBounds(745, 720, 80, 30);
	   tf=new JTextField();
	   tf.setBounds(830, 730, 150, 30);
	   
	   add(la1);add(tf);
	   
	   la2=new JLabel("대화명",JLabel.RIGHT);
	   la2.setBounds(745, 765, 80, 30);
	   pf=new JTextField();
	   pf.setBounds(830, 765, 150, 30);
	   // 980-745= 235
	   add(la2);add(pf);
	   
	   rb1 = new JRadioButton("남자");
	   rb2 = new JRadioButton("여자");
	   ButtonGroup bg = new ButtonGroup();
	   bg.add(rb1); bg.add(rb2);
	   rb1.setSelected(true);
	   la3 = new JLabel("성별",JLabel.RIGHT);
	   la3.setBounds(745, 800, 80, 30);
	   rb1.setBounds(830, 800, 70, 30);
	   rb2.setBounds(910, 800, 70, 30);
	   add(la3);add(rb1);add(rb2);
			   
	   b1=new JButton("로그인");
	   b2=new JButton("취소");
	   JPanel p=new JPanel();
	   p.add(b1);
	   p.add(b2);
	   p.setOpaque(false);
	   p.setBounds(745, 850, 235, 35);
	   add(p);
	   
	   
   }
	@Override
	protected void paintComponent(Graphics g) {
		g.drawImage(back,0,0,getWidth(),getHeight(),this);
	}
   
}

 

ClientMainFrame

package com.sist.client;
import java.util.*;
import javax.swing.*;

import com.sist.common.Function;

import java.awt.*;
import java.awt.event.*;
////////////////// 네트워크 관련
import java.net.*;
import java.io.*;
public class ClientMainFrame extends JFrame implements ActionListener, Runnable{
	CardLayout card = new CardLayout();
	Login login = new Login();
	WaitRoom wr = new WaitRoom();
	// 네트워크 
	Socket s; // 전화기
	BufferedReader in; // 수신
	OutputStream out; // 송신
	
	public ClientMainFrame() {
		setLayout(card);
		add("LOGIN",login);
		add("WR",wr);
		
		setSize(1200,950);
		setVisible(true);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		
		login.b1.addActionListener(this);
		login.b2.addActionListener(this);
		
		wr.tf.addActionListener(this);
		
	}
	public static void main(String[] args) {
		new ClientMainFrame();
		
	}
	public void connection(String id, String name, String sex) {
		// 서버연결 => 로그인 요청
		try {
			s = new Socket("localhost",9875); //서버주소, PORT
			in = new BufferedReader(new InputStreamReader(s.getInputStream()));
			out = s.getOutputStream();
			
			// 연결이 되면 로그인요청
			out.write((Function.LOGIN+"|"+id+"|"+name+"|"+sex+"\n").getBytes());
		}catch(Exception ex) {}
		// 연결이 되면 => 서버부터 지시를 받는다
		new Thread(this).start();
		
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource()==login.b1) {
			String id = login.tf.getText();
			String name = login.pf.getText();
			String sex = "";
			if(login.rb1.isSelected())
				sex="남자";
			else
				sex="여자";
			connection(id, name, sex);
		}
		else if(e.getSource()==wr.tf) {
			// 입력된 데이터 읽기
			String msg = wr.tf.getText();
			if(msg.length()<1) return;
			
			try {
				out.write((Function.WAITCHAT+"|"+msg+"\n").getBytes());				
			}catch(Exception ex) {}
			
			wr.tf.setText("");
		}
	}
	@Override
	public void run() {
		try {
			while(true) {
				String msg = in.readLine();
				StringTokenizer st = new StringTokenizer(msg, "|");
				int protocol = Integer.parseInt(st.nextToken());
				switch(protocol) {
				case Function.LOGIN:{
					String[] data = {
							st.nextToken(),
							st.nextToken(),
							st.nextToken(),
							st.nextToken(),
					};
					wr.model2.addRow(data);
				}
				break;
				case Function.MYLOG:{
					setTitle(st.nextToken());
					card.show(getContentPane(), "WR");
				}
				break;
				case Function.WAITCHAT:
				{
					wr.bar.setValue(wr.bar.getMaximum());
					wr.ta.append(st.nextToken()+"\n");
				}
				break;
				}
			}
		}catch(Exception ex) {}
		
	}

}
반응형
Comments