본문으로 바로가기

[자바]채팅프로그램 만들기

category Java 2017. 8. 17. 21:09

안녕하세요.


오늘은 자바를 이용해 채팅프로그램을 만들어 보았습니다.


아직 오류도많고 너무 막? 코딩을 한 상태라 부족한부분이 매우매우매우매우 많습니다.


그래도 이런 채팅 프로그램을보고 도움이 될수도 있다면 정말 좋겠네요.


이번 채팅프로그램은 간단한 이모티콘을 보낼수 있고, 강퇴투표기능, 귓속말, 닉네임변경 기능이 있습니다.


클래스는 크게 4개로 구성됩니다.


MultiServer, MultiServerThread, MultiClient, MultiClientThread


서버클래스2개와 클라이언트클래스2개입니다.


서버클래스에서는 투표수를 관리하고 클라이언트와의 통신이 가능한 소켓을 생성합니다.


대부분의 기능은 클라이언트쓰레드에서 나오는데요.


사용자가보낸 명령에 맞춰 여러가지 기능들이 가능하게 되어있습니다.


닉네임변경은 /change 바꿀닉네임 , 귓속말은 /w 대상닉네임 할말 

강퇴투표는 /vote 닉네임 이런식입니다.


이모티콘의 출력(이미지의 출력) 을 위해 JTextArea 대신 JTextPane 을 사용하였습니다.


MultiServer.class

package multiserver;

import java.io.*;
import java.net.*;
import java.util.*;

public class MultiServer {
	private ArrayList list;
	private Socket socket;

	public MultiServer() throws IOException {
		list = new ArrayList();
		ServerSocket serverSocket = new ServerSocket(5000);
		MultiServerThread mst = null;
		boolean isStop = false;
		while (!isStop) {
			System.out.println("Server ready...");
			socket = serverSocket.accept();
			mst = new MultiServerThread(this);
			list.add(mst);
			Thread t = new Thread(mst);
			t.start();
		}
	}

	public ArrayList getList() {
		return list;
	}

	public Socket getSocket() {
		return socket;
	}

	public static void main(String arg[]) throws IOException {
		new MultiServer();
	}
}

MultiServerThread

package multiserver;

import java.net.*;
import java.io.*;

public class MultiServerThread implements Runnable {
	private Socket socket;
	private MultiServer ms;
	private ObjectInputStream ois;
	private ObjectOutputStream oos;
	private int count = 0, count1 = 0;

	public MultiServerThread(MultiServer ms) {
		this.ms = ms;
	}

	public synchronized void run() {
		boolean isStop = false;
		try {
			socket = ms.getSocket();
			ois = new ObjectInputStream(socket.getInputStream());
			oos = new ObjectOutputStream(socket.getOutputStream());
			String message = null;
			while (!isStop) {
				message = (String) ois.readObject();
				String[] str = message.split("#");
				if (str[1].equals("exit")) {
					broadCasting(message);
					isStop = true;
				}else if(str[1].equals("voteag")) {
					broadCasting("vote"+"#"+(count+1)+"/"+ms.getList().size()+"투표완료"+"#"+"ag" +"#" + count + "#" + count1);
				}else if(str[1].equals("voteop")) {
					broadCasting("vote"+"#"+(count+1)+"/"+ms.getList().size()+"투표완료"+"#"+"op"+"#" + count + "#" + count1);
				}else if(str[0].equals("count")){
					count = Integer.parseInt(str[1]);
					count1 = Integer.parseInt(str[2]);
				}else {
					broadCasting(message);
				}
				
				if(count >= ms.getList().size()) {
					if(ms.getList().size()/2+1 <= count1) {
						broadCasting("voteresult"+"#"+"voteag");
					}else {
						broadCasting("voteresult"+"#"+"voteop");
					}
					count = 0;
					count1 = 0;
				}
			}
			ms.getList().remove(this);
			System.out.println(socket.getInetAddress() + "정상적으로 종료하셨습니다");
			System.out.println("list size : " + ms.getList().size());
		} catch (Exception e) {
			ms.getList().remove(this);
			System.out.println(socket.getInetAddress() + "비정상적으로 종료하셨습니다");
			System.out.println("list size : " + ms.getList().size());
		}
	}

	public void broadCasting(String message) throws IOException {
		for (MultiServerThread ct : ms.getList()) {
			ct.send(message);
		}
	}

	public void send(String message) throws IOException {
		oos.writeObject(message);
	}

}

MultiClient

package multiserver;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;


public class MultiClient implements ActionListener {
	private Socket socket;
	private ObjectInputStream ois;
	private ObjectOutputStream oos;
	private JFrame jframe,votf;
	private JTextField jtf;
	// private JTextArea jta;
	private JLabel jlb1, jlb2, jlb3;
	private JPanel jp1, jp2;
	private String ip;
	private String id;
	private JButton jbtn,bt1,bt2;
	private JTextPane jtp;
	private ImageIcon image;
	
	public MultiClient(String argIp, String argId) {
		ip = argIp;
		id = argId;

		image = new ImageIcon("src/img/background.jpg");
		jframe = new JFrame("Multi Chatting");
		jtf = new JTextField(30);
		// jta = new JTextArea("", 10, 50);
		jtp = new JTextPane();
		jtp.setPreferredSize(new Dimension(100, 500));
		jlb1 = new JLabel("Usage ID : [ " + id + "]");
		jlb2 = new JLabel();
		jlb3 = new JLabel("IP : " + ip);
		jbtn = new JButton("이모티콘");
		jp1 = new JPanel();
		jp2 = new JPanel();
		jlb1.setBackground(Color.yellow);
		jlb2.setBackground(Color.gray);
		jlb3.setBackground(Color.green);
		// jta.setBackground(Color.pink);
		jtp.setBackground(Color.yellow);
		jp1.setLayout(new BorderLayout());
		jp2.setLayout(new BorderLayout());
		jp1.add(jbtn, BorderLayout.EAST);
		jp1.add(jtf, BorderLayout.CENTER);
		jp2.add(jlb1, BorderLayout.WEST);
		jp2.add(jlb2, BorderLayout.CENTER);
		jp2.add(jlb3, BorderLayout.EAST);
		jframe.add(jp1, BorderLayout.SOUTH);
		jframe.add(jp2, BorderLayout.NORTH);
		// JScrollPane jsp = new JScrollPane(jta, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
		// JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		// jframe.add(jsp, BorderLayout.CENTER);
		JScrollPane jsp = new JScrollPane(jtp, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
				JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		jframe.add(jsp, BorderLayout.CENTER);

		jtf.addActionListener(this);
		jbtn.addActionListener(this);
		jframe.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				try {
					oos.writeObject(id + "#exit"); // x표시로 종료이벤트가 발생하면 id+#exit 아웃스트림으로 전송
				} catch (IOException ee) {
					ee.printStackTrace();
				}
				System.exit(0);
			}

			public void windowOpened(WindowEvent e) {
				jtf.requestFocus(); // 창이열리면 글쓰는공간에 포커스맞춰짐
			}
		});
		// jta.setEditable(false);
		jtp.setEditable(false);
		Toolkit tk = Toolkit.getDefaultToolkit();
		Dimension d = tk.getScreenSize();
		int screenHeight = d.height;
		int screenWidth = d.width;
		jframe.pack();
		jframe.setLocation((screenWidth - jframe.getWidth()) / 2, (screenHeight - jframe.getHeight()) / 2);
		jframe.setResizable(false);
		jframe.setVisible(true);
	}

	public void actionPerformed(ActionEvent e) {
		Object obj = e.getSource(); // 누른것의 객체를 obj 에 저장
		String msg = jtf.getText();
		if (obj == jtf) { // 누른것이 텍스트필드이면
			if (msg == null || msg.length() == 0) { // 글을 쓰지않으면 경고창 띄워줌
				JOptionPane.showMessageDialog(jframe, "글을쓰세요", "경고", JOptionPane.WARNING_MESSAGE);
			} else { // 글이있으면 id + # + 내용 을 아웃스트림전송
				try {
					oos.writeObject(id + "#" + msg);
				} catch (IOException ee) {
					ee.printStackTrace();
				}
				jtf.setText(""); // 글을쓰면 텍스트필드 초기화
			}
		} else if (obj == jbtn) { // 누른것이 이모티콘버튼이면
			try {
				oos.writeObject(id + "#" + "imo");
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		} else if(obj == bt1) {
			System.out.println(bt1.getText());
			try {
				oos.writeObject(id + "#" + "voteag");
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			votf.dispose();
		}else if(obj == bt2){
			System.out.println(bt2.getText());
			try {
				oos.writeObject(id + "#" + "voteop");
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			votf.dispose();
		}
	}

	public void exit() {
		System.exit(0);
	}

	public void init() throws IOException {
		socket = new Socket(ip, 5000);
		System.out.println("connected...");
		oos = new ObjectOutputStream(socket.getOutputStream());
		ois = new ObjectInputStream(socket.getInputStream());
		MultiClientThread ct = new MultiClientThread(this);
		Thread t = new Thread(ct);
		t.start();
	}

	public static void main(String args[]) throws IOException {
		MultiClient cc = new MultiClient("172.22.233.150","dd");
		cc.init();
	}

	public ObjectInputStream getOis() {
		return ois;
	}
	
	public ObjectOutputStream getOos() {
		return oos;
	}

	public JTextPane getJtp() {
		return jtp;
	}
	
	public JLabel getJlb1() {
		return jlb1;
	}
	
	public void setImo() {
		jtp.insertIcon(new ImageIcon("src/img/imo1.png"));
		append(System.getProperty("line.separator"));
	}
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public void append(String s) {
		try {
			Document doc = jtp.getDocument();
			doc.insertString(doc.getLength(), s, null);
		} catch (BadLocationException exc) {
			exc.printStackTrace();
		}
	}
	
	public void vote() {
		votf = new JFrame("강퇴투표");
		votf.setBounds(900, 500, 100, 100);;
		bt1 = new JButton("찬성");
		bt2 = new JButton("반대");
		votf.add(bt1,BorderLayout.WEST);
		votf.add(bt2,BorderLayout.EAST);
		votf.setVisible(true);
		bt1.addActionListener(this);
		bt2.addActionListener(this);
	}
}


MultiClientThread

package multiserver; import java.io.IOException; public class MultiClientThread extends Thread { private int count = 0, count1 = 0; private MultiClient mc; public MultiClientThread(MultiClient mc) { this.mc = mc; } public void run() { String message = null; String votename = null; String[] receivedMsg = null, wmessage = null; boolean voteck = false; boolean isStop = false; while (!isStop) { try { message = (String) mc.getOis().readObject(); // message 에 닉네임#내용 << 으로 저장 System.out.println(message); receivedMsg = message.split("#"); // receivedMsg[0] 닉네임 , receivedMsg[1] 내용 wmessage = receivedMsg[1].split(" "); } catch (Exception e) { e.printStackTrace(); isStop = true; } System.out.println(receivedMsg[0] + "," + receivedMsg[1]); // 닉네임,내용 으로 표시 if (receivedMsg[1].equals("exit")) { // 내용이 exit 이면 if (receivedMsg[0].equals(mc.getId())) { // 닉네임비교후 내꺼면 종료 아니면 ta에 종료텍스트출력 mc.exit(); } else { mc.append(receivedMsg[0] + "님이 종료 하셨습니다." + System.getProperty("line.separator")); mc.getJtp().setCaretPosition(mc.getJtp().getDocument().getLength()); } } else if (receivedMsg[0].equals("vote")) { // 내용이 /vote 이면 if(receivedMsg[2].equals("ag")) { count1 = Integer.parseInt(receivedMsg[4])+1; }else if(receivedMsg[2].equals("op")){ count1 = Integer.parseInt(receivedMsg[4]); } count = Integer.parseInt(receivedMsg[3])+1; try { mc.getOos().writeObject("count#"+count+"#"+count1); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } mc.append(receivedMsg[1] + System.getProperty("line.separator")); } else if (receivedMsg[0].equals("voteresult")) { // 내용이 /voteresult 이면 count = 0; if (receivedMsg[1].equals("voteag")) { if (votename.equals(mc.getId())) { mc.exit(); }else { mc.append(votename + "님이 강퇴 당하였습니다." + System.getProperty("line.separator")); mc.getJtp().setCaretPosition(mc.getJtp().getDocument().getLength()); } } else if (receivedMsg[1].equals("voteop")) { mc.append("강퇴가 반대 되었습니다." + System.getProperty("line.separator")); mc.getJtp().setCaretPosition(mc.getJtp().getDocument().getLength()); } } else if (wmessage[0].equals("/w")) { // 내용이 /w 이면 if (wmessage[1].equals(mc.getId())) { mc.append(wmessage[1] + "<<" + receivedMsg[0] + " : " + wmessage[2] + System.getProperty("line.separator")); } if (receivedMsg[0].equals(mc.getId())) { mc.append(receivedMsg[0] + ">>" + wmessage[1] + " : " + wmessage[2] + System.getProperty("line.separator")); } } else if (wmessage[0].equals("/change")) { // 내용이 /change 이면 if (receivedMsg[0].equals(mc.getId())) { mc.setId(wmessage[1]); mc.getJlb1().setText("Usage ID : [ " + mc.getId() + "]"); } mc.append(receivedMsg[0] + "님이 닉네임을 변경하였습니다. (" + receivedMsg[0] + " >> " + wmessage[1] + ")" + System.getProperty("line.separator")); } else if (wmessage[0].equals("imo")) { // 내용이 /imo 이면 mc.setImo(); mc.getJtp().setCaretPosition(mc.getJtp().getDocument().getLength()); } else if (wmessage[0].equals("/vote")) { // 내용이 /vote 이면 mc.append(wmessage[1] + "님의 강퇴 투표가 시작되었습니다." + System.getProperty("line.separator")); votename = wmessage[1]; voteck = true; } else { // 내용이 exit 가 아니면 ta 에 내용출력 mc.append(receivedMsg[0] + " : " + receivedMsg[1] + System.getProperty("line.separator")); mc.getJtp().setCaretPosition(mc.getJtp().getDocument().getLength()); } if (voteck) { mc.vote(); voteck = false; } } } }


문제가 많은 코드입니다 ...


참고용으로만 봐주세요ㅜㅜ 감사합니다.


//개스레기코드


댓글을 달아 주세요

  1. 아랑 2019.06.02 16:55

    정말 고마웠어유.

  2. 하인츠 2019.08.26 20:52

    MultiServerThread에서 62번행의 'for (MultiServerThread ct : ms.getList()) {' 에서 'ms.getList()'에서 에러가 났습니다.

    public void broadCasting(String message) throws IOException {
    for (MultiServerThread ct : ms.getList()) {
    ct.send(message);

  3. yh 2021.10.02 20:32

    이거 실행 어떻게해요...?