일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 빅분기 독학
- 빅분기 필기
- 원씽 책
- 노트패드 줄바꿈
- The OneThing
- 빅데이터분석기사 독학
- 원씽 독후감
- 빅데이터분석기사
- 노트패드++ 줄바꿈
- 동기식 비동기식
- ajax 비동기식
- 자바스크립트 undefined
- 자바 채팅 프로그램
- TCP Socket
- dom sax 차이점
- 원씽 후기
- async
- Notepad 줄바꿈
- TCP 채팅
- 빅데이터분석기사 필기
- 자바 채팅
- dom sax 장단점
- xml 파싱 방법
- 책 원씽
- 원씽 내용
- async false
- ajax 동기식
- Notepad++ 줄바꿈
- 간단한 채팅 프로그램
- 빅분기
Archives
- Today
- Total
SooBlending
[TCP Socket] 간단한 채팅 프로그램 (Server/Client) 본문
== > 아직 이벤트 처리 안한 부분의 버튼도 있지만 기본적으로 서버를 열고 클라이언트로 접속을 하여 채팅이 가능하다.
< Room.java >
import java.util.Vector;
public class Room {//대화방의 정보표현 객체
String title;//방제목
int count;//방 인원수
String boss;//방장(방 개설자)
Vector<Service> userV;//userV: 같은 방에 접속한 Client정보 저장
public Room() {
userV = new Vector<>();
}
}
< Server.java >
import java.io.IOException;import
java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
public class Server implements Runnable{
//Server클래스: 소켓을 통한 접속서비스, 접속클라이언트 관리
Vector<Service> allV; //모든 사용자(대기실사용자 + 대화방사용자)
Vector<Service> waitV; //대기실 사용자
Vector<Room> roomV; //개설된 대화방 Room-vs(Vector) : 대화방사용자
public Server() {
allV = new Vector<>();
waitV = new Vector<>();
roomV = new Vector<>();
//Thread t = new Thread(run메소드의 위치);
t.start();
new Thread(this).start();
}//생성자
@Override public void run(){
try {
ServerSocket ss = new ServerSocket(5000); //현재 실행중인 ip + 명시된 port ----> 소켓서비스
System.out.println("Start Server......."); while(true){ Socket s = ss.accept();//클라이언트 접속 대기 //s: 접속한 클라이언트의 소켓정보 Service ser = new Service(s, this); //allV.add(ser);//전체사용자에 등록 //waitV.add(ser);//대기실사용자에 등록 } } catch (IOException e) { e.printStackTrace(); } }//run
public static void main(String[] args) {
new Server();
}
}
< Service.java >
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Vector;
public class Service extends Thread{ //Service == 접속 클라이언트 한명!!
Room myRoom;//클라이언트가 입장한 대화방
//소켓관련 입출력서비스
BufferedReader in;
OutputStream out;
Vector<Service> allV; //모든 사용자(대기실사용자 + 대화방사용자)
Vector<Service> waitV; //대기실 사용자
Vector<Room> roomV; //개설된 대화방 Room-vs(Vector) : 대화방사용자
Socket s;
String nickName;
public Service(Socket s, Server server) {
allV=server.allV;
waitV=server.waitV;
roomV=server.roomV;
this.s = s;
try {
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
out = s.getOutputStream();
start();
} catch (IOException e) {
e.printStackTrace();
}
}//생성자
@Override
public void run() {
try {
while(true){
String msg = in.readLine();//클라이언트의 모든 메시지를 받기
if(msg == null) return; //비정상적인 종료
if(msg.trim().length() > 0){
System.out.println("from Client: "+ msg +":"+
s.getInetAddress().getHostAddress());//서버에서 상황을 모니터!!
String msgs[]=msg.split("\\|");
String protocol = msgs[0];
switch(protocol){
case "100": //대기실 접속
allV.add(this);//전체사용자에 등록
waitV.add(this);//대기실사용자에 등록
break;
case "150": //대화명 입력
nickName=msgs[1];
//최초 대화명 입력했을때 대기실의 정보를 출력
messageWait("160|"+ getRoomInfo());
messageWait("180|"+ getWaitInwon());
break;
case "160": //방만들기 (대화방 입장)
myRoom = new Room();
myRoom.title =msgs[1];//방제목
myRoom.count = 1;
myRoom.boss = nickName;
roomV.add(myRoom);
//대기실----> 대화방 이동!!
waitV.remove(this);
myRoom.userV.add(this);
messageRoom("200|"+nickName);//방인원에게 입장 알림
//대기실 사용자들에게 방정보를 출력
//예) 대화방명:JavaLove
//-----> roomInfo(JList) : JavaLove--1
messageWait("160|"+ getRoomInfo());
messageWait("180|"+ getWaitInwon());
break;
case "170": //(대기실에서) 대화방 인원정보
messageTo("170|"+getRoomInwon(msgs[1]));
break;
case "175": //(대화방에서) 대화방 인원정보
messageRoom("175|"+getRoomInwon());
break;
case "200": //방들어가기 (대화방 입장) ---->
msgs[] = {"200","자바방"}
for(int i=0; i<roomV.size(); i++){//방이름 찾기!!
Room r = roomV.get(i);
if(r.title.equals(msgs[1])){//일치하는 방 찾음!!
myRoom = r;
myRoom.count++;//인원수 1증가
break;
}
}//for
//대기실----> 대화방 이동!!
waitV.remove(this);
myRoom.userV.add(this);
messageRoom("200|"+nickName);//방인원에게 입장 알림
//들어갈 방의 title전달
messageTo("202|"+ myRoom.title);
messageWait("160|"+ getRoomInfo());
messageWait("180|"+ getWaitInwon());
break;
case "300": //메시지
messageRoom("300|["+nickName +"]▶ "+msgs[1]);
//클라이언트에게 메시지 보내기
break;
case "400": //대화방 퇴장
myRoom.count--;//인원수 감소
messageRoom("400|"+nickName);//방인원들에게 퇴장 알림!!
//대화방----> 대기실 이동!!
myRoom.userV.remove(this);
waitV.add(this);
//대화방 퇴장후 방인원 다시출력
messageRoom("175|"+getRoomInwon());
//대기실에 방정보 다시출력
messageWait("160|"+ getRoomInfo());
break;
}//서버 switch }//if }//while
}catch (IOException e) {
System.out.println("★"); e.printStackTrace();
}
}//run
public String getRoomInfo(){
String str="";
for(int i=0; i<roomV.size(); i++){
//"자바방--1,오라클방--1,JDBC방--1"
Room r= roomV.get(i);
str += r.title+"--"+r.count;
if(i<roomV.size()-1)str += ",";
}
return str;
}//getRoomInfo
public String getRoomInwon(){//같은방의 인원정보
String str="";
for(int i=0; i<myRoom.userV.size(); i++){
//"길동,라임,주원"
Service ser= myRoom.userV.get(i);
str += ser.nickName;
if(i<myRoom.userV.size()-1)str += ",";
}
return str;
}//getRoomInwon
public String getRoomInwon(String title){//방제목 클릭시 방의 인원정보
String str="";
for(int i=0; i<roomV.size(); i++){
//"길동,라임,주원"
Room room = roomV.get(i);
if(room.title.equals(title)){
for(int j=0; j<room.userV.size(); j++){
Service ser= room.userV.get(j);
str += ser.nickName;
if(j<room.userV.size()-1)str += ",";
} break;
}
}
return str;
}//getRoomInwon
public String getWaitInwon(){
String str="";
for(int i=0; i<waitV.size(); i++){ //"길동,라임,주원"
Service ser= waitV.get(i);
str += ser.nickName;
if(i<waitV.size()-1)str += ",";
} return str;
}//getWaitInwon
public void messageAll(String msg){//전체사용자
//접속된 모든 클라이언트(대기실+대화방)에게 메시지 전달
for(int i=0; i<allV.size(); i++){//벡터 인덱스
Service service = allV.get(i); //각각의 클라이언트 얻어오기
try {
service.messageTo(msg);
} catch (IOException e) { //에러발생 ---> 클라이언트 접속 끊음!!
allV.remove(i--); //접속 끊긴 클라이언트를 벡터에서 삭제!!
System.out.println("클라이언트 접속 끊음!!");
}
}
}//messageAll
public void messageWait(String msg){//대기실 사용자
for(int i=0; i<waitV.size(); i++){//벡터 인덱스
Service service = waitV.get(i); //각각의 클라이언트 얻어오기
try {
service.messageTo(msg);
} catch (IOException e) { //에러발생 ---> 클라이언트 접속 끊음!!
waitV.remove(i--); //접속 끊긴 클라이언트를 벡터에서 삭제!!
System.out.println("클라이언트 접속 끊음!!");
}
}
}//messageWait
public void messageRoom(String msg){//대화방사용자
for(int i=0; i< myRoom.userV.size(); i++){//벡터 인덱스
Service service = myRoom.userV.get(i); //각각의 클라이언트 얻어오기
try {
service.messageTo(msg);
} catch (IOException e) { //에러발생 ---> 클라이언트 접속 끊음!!
myRoom.userV.remove(i--); //접속 끊긴 클라이언트를 벡터에서 삭제!!
System.out.println("클라이언트 접속 끊음!!");
}
}
}//messageAll
public void messageTo(String msg) throws IOException{//특정 클라이언트에게 메시지 전달 (실제 서버--->클라이언트 메시지 전달)
out.write( (msg+"\n").getBytes() );
}
}
< ChatClient.java >
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ChatClient extends JFrame{
//채팅방
JTextField sendTF;
JLabel la_msg;
JTextArea ta;
JScrollPane sp_ta,sp_list;
JList<String> li_inwon;
JButton bt_change,bt_exit;
JPanel p;
public ChatClient() {
setTitle("채팅방");
sendTF = new JTextField(15);
la_msg = new JLabel("Message");
ta = new JTextArea();
ta.setLineWrap(true);//TextArea 가로길이를 벗어나는 text발생시 자동 줄바꿈
li_inwon = new JList<String>();
sp_ta = new JScrollPane(ta);
sp_list = new JScrollPane(li_inwon);
bt_change = new JButton("대화명변경");
bt_exit = new JButton("나가기");
p = new JPanel();
sp_ta.setBounds(10,10,380,390);
la_msg.setBounds(10,410,60,30);
sendTF.setBounds(70,410,320,30);
sp_list.setBounds(400,10,120,350);
bt_change.setBounds(400,370,120,30);
bt_exit.setBounds(400,410,120,30);
p.setLayout(null);
p.setBackground(Color.PINK);
p.add(sp_ta);
p.add(la_msg);
p.add(sendTF);
p.add(sp_list);
p.add(bt_change);
p.add(bt_exit);
add(p);
setBounds(300,200,550,500);
//setVisible(true);
sendTF.requestFocus();
}//생성자
}
< MainChat.java >
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.TitledBorder;
public class MainChat extends JFrame implements ActionListener, Runnable{
JList<String> roomInfo,roomInwon,waitInfo;
JScrollPane sp_roomInfo, sp_roomInwon, sp_waitInfo;
JButton bt_create, bt_enter, bt_exit;
JPanel p;
ChatClient cc;
//소켓 입출력객체
BufferedReader in;
OutputStream out;
String selectedRoom;
public MainChat() {
setTitle("대기실");
cc = new ChatClient();
roomInfo = new JList<String>();
roomInfo.setBorder(new TitledBorder("방정보"));
roomInfo.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
String str = roomInfo.getSelectedValue(); //"자바방--1"
if(str==null)return;
System.out.println("STR="+str);
selectedRoom = str.substring(0, str.indexOf("-"));
//"자바방" <---- substring(0,3)
//대화방 내의 인원정보
sendMsg("170|"+selectedRoom);
}
});
roomInwon = new JList<String>();
roomInwon.setBorder(new TitledBorder("인원정보"));
waitInfo = new JList<String>();
waitInfo.setBorder(new TitledBorder("대기실정보"));
sp_roomInfo = new JScrollPane(roomInfo);
sp_roomInwon = new JScrollPane(roomInwon);
sp_waitInfo = new JScrollPane(waitInfo);
bt_create = new JButton("방만들기");
bt_enter = new JButton("방들어가기");
bt_exit = new JButton("나가기");
p = new JPanel();
sp_roomInfo.setBounds(10, 10, 300, 300);
sp_roomInwon.setBounds(320, 10, 150, 300);
sp_waitInfo.setBounds(10, 320, 300, 130);
bt_create.setBounds(320,330,150,30);
bt_enter.setBounds(320,370,150,30);
bt_exit.setBounds(320,410,150,30);
p.setLayout(null);
p.setBackground(Color.orange);
p.add(sp_roomInfo);
p.add(sp_roomInwon);
p.add(sp_waitInfo);
p.add(bt_create);
p.add(bt_enter);
p.add(bt_exit);
add(p);
setBounds(300,200, 500, 500);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
connect();//서버연결시도 (in,out객체생성)
new Thread(this).start();//서버메시지 대기
sendMsg("100|");//(대기실)접속 알림
String nickName = JOptionPane.showInputDialog(this,"대화명:");
sendMsg("150|"+nickName);//대화명 전달
eventUp();
}//생성자
private void eventUp(){//이벤트소스-이벤트처리부 연결
//대기실(MainChat)
bt_create.addActionListener(this);
bt_enter.addActionListener(this);
bt_exit.addActionListener(this);
//대화방(ChatClient)
cc.sendTF.addActionListener(this);
cc.bt_change.addActionListener(this);
cc.bt_exit.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
Object ob = e.getSource();
if(ob==bt_create){//방만들기 요청
String title = JOptionPane.showInputDialog(this,"방제목:");
//방제목을 서버에게 전달
sendMsg("160|"+title);
cc.setTitle("채팅방-["+title+"]");
sendMsg("175|");//대화방내 인원정보 요청
setVisible(false);
cc.setVisible(true); //대화방이동
}else if(ob==bt_enter){//방들어가기 요청
if(selectedRoom == null){
JOptionPane.showMessageDialog(this, "방을 선택!!");
return;
}
sendMsg("200|"+ selectedRoom);
sendMsg("175|");//대화방내 인원정보 요청
setVisible(false);
cc.setVisible(true);
}else if(ob==cc.bt_exit){//대화방 나가기 요청
sendMsg("400|");
cc.setVisible(false);
setVisible(true);
}else if(ob==cc.sendTF){//(TextField입력)메시지 보내기 요청
String msg = cc.sendTF.getText();
if(msg.length()>0){
sendMsg("300|"+msg);
cc.sendTF.setText("");
}
}
else if(ob==bt_exit){//나가기(프로그램종료) 요청
System.exit(0);//현재 응용프로그램 종료하기
}
}//actionPerformed
public void connect(){//(소켓)서버연결 요청
try {
//Socket s = new Socket(String host<서버ip>, int port<서비스번호>);
Socket s = new Socket("localhost", 5000);//연결시도
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
//in: 서버메시지 읽기객체 서버-----msg------>클라이언트
out = s.getOutputStream();
//out: 메시지 보내기, 쓰기객체 클라이언트-----msg----->서버
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}//connect
public void sendMsg(String msg){//서버에게 메시지 보내기
try {
out.write( (msg+"\n").getBytes() );
}catch (IOException e) {
e.printStackTrace();
}
}//sendMsg
public void run(){//서버가 보낸 메시지 읽기
//왜 run메소드 사용? GUI프로그램실행에 영향 미치지않는 코드 작성.
//메소드호출은 순차적인 실행!! 스레드메소드는 동시실행(기다리지 않는 별도 실행)!!
try {
while(true){
String msg = in.readLine();//msg: 서버가 보낸 메시지
//msg==> "300|안녕하세요" "160|자바방--1,오라클방--1,JDBC방--1"
String msgs[] = msg.split("\\|");
String protocol = msgs[0];
switch(protocol){
case "300":
cc.ta.append(msgs[1]+"\n");
cc.ta.setCaretPosition(cc.ta.getText().length());
break;
case "160"://방만들기
//방정보를 List에 뿌리기
if(msgs.length > 1){
//개설된 방이 한개 이상이었을때 실행
//개설된 방없음 ----> msg="160|" 였을때 에러
String roomNames[] = msgs[1].split(",");
//"자바방--1,오라클방--1,JDBC방--1"
roomInfo.setListData(roomNames);
}
break;
case "170"://(대기실에서) 대화방 인원정보
String roomInwons[] = msgs[1].split(",");
roomInwon.setListData(roomInwons);
break;
case "175"://(대화방에서) 대화방 인원정보
String myRoomInwons[] = msgs[1].split(",");
cc.li_inwon.setListData(myRoomInwons);
break;
case "180"://대기실 인원정보
String waitNames[] = msgs[1].split(",");
waitInfo.setListData(waitNames);
break;
case "200"://대화방 입장
cc.ta.append("=========["+msgs[1]+"]님 입장=========\n");
cc.ta.setCaretPosition(cc.ta.getText().length());
break;
case "400"://대화방 퇴장
cc.ta.append("=========["+msgs[1]+"]님 퇴장=========\n");
cc.ta.setCaretPosition(cc.ta.getText().length());
break;
case "202"://개설된 방의 타이틀 제목 얻기
cc.setTitle("채팅방-["+msgs[1]+"]");
break;
}//클라이언트 switch
}
}catch (IOException e) {
e.printStackTrace();
}
}//run
public static void main(String[] args) {
new MainChat();
}
}
'Programming > Java' 카테고리의 다른 글
[Java] Properties / Enumeration (0) | 2017.11.17 |
---|---|
[JDBC] Eclipse와 DB 연결하기 (Oracle) (0) | 2017.11.14 |
[TCP Socket ] TCP 소켓 통신 (0) | 2017.11.07 |
[Eclipse] 이클립스 단축키 (0) | 2017.11.07 |
Comments