간단한 채팅 프로그램 만들기


- 다대다 클라이언트 간의 채팅

- 서버는 클라이언트에게 메시지를 뿌려주는 역할




[Server]

package tcp4;


import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.IOException;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.ArrayList;

import java.util.List;


public class Server {


ServerSocket serSock;

List<Socket> sockList;


public Server() throws IOException {

serSock = new ServerSocket(10081);

sockList = new ArrayList<>();

}


public void all_client_write(Socket sock, String msg) {


BufferedOutputStream bos = null;

try {

String info = "[" + sock.getRemoteSocketAddress() + "] : ";

for (int i = 0; i < sockList.size(); i++) {

bos = new BufferedOutputStream(sockList.get(i).getOutputStream());

System.out.println("send to " + sockList.get(i).toString() + ":" + msg);


String inFoMsg = info + msg;

bos.write(inFoMsg.getBytes("UTF-8"));

bos.flush();


}


} catch (IOException e) {

// TODO Auto-generated catch block

try {

bos.close();

sock.close();

removeSock(sock);

} catch (IOException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}


System.out.println("server write exception!");


e.printStackTrace();

}


}


public void stop(Thread thread) {

thread.interrupt();

}

public void removeSock(Socket sock) {

System.out.println("socket is close");

System.out.println("====================================");

System.out.println("현재 접속: " + sockList.size());

for (int i = 0; i < sockList.size(); i++) {

if (sockList.get(i) == sock) {

try {

sockList.get(i).close();

sockList.remove(i);

break;

} catch (IOException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}


}

}

for (int i = 0; i < sockList.size(); i++) {

System.out.println(sockList.get(i).toString());

}

System.out.println("====================================\n\n");


}


public void read(Socket sock) {

Thread thread = null;


thread = new Thread(new Runnable() {


@Override

public void run() {

// TODO Auto-generated method stub

BufferedInputStream bis = null;

boolean flag = true;

try {

while (flag) {


bis = new BufferedInputStream(sock.getInputStream());

byte b[] = new byte[256];

int data = bis.read(b);


if (data != 0) {

String msg = new String(b);

System.out.println("[" + sock.getLocalAddress() + "] : " + msg);


all_client_write(sock, msg);

}


}

} catch (IOException e) {

// TODO Auto-generated catch block

try {

sock.close();

removeSock(sock);

} catch (IOException e2) {

// TODO Auto-generated catch block

e2.printStackTrace();

}

}


}


});


thread.start();


}


public void startServer() {

System.out.println("start Server!");

Thread thread = new Thread(new Runnable() {


@Override

public void run() {

// TODO Auto-generated method stub

try {

while (true) {

Socket sock = null;

sock = serSock.accept();

sockList.add(sock);


System.out.println("====================================");

System.out.println("현재 접속: " + sockList.size());

for (int i = 0; i < sockList.size(); i++) {

System.out.println(sockList.get(i).toString());

}

System.out.println("====================================\n\n");


read(sock);

}


} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

System.out.println("socket accept excpetion");

return;

}

}

});

thread.start();


}


public static void main(String[] args) {

// TODO Auto-generated method stub

try {

new Server().startServer();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

System.out.println("server start exception");

}

}


}

[Client]

package tcp4;


import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.IOException;

import java.net.InetSocketAddress;

import java.net.Socket;

import java.net.UnknownHostException;

import java.util.Scanner;


public class Client {


Socket sock;

String host;

int port;


public void connect() throws UnknownHostException, IOException {

host = "localhost";

port = 10081;

sock = new Socket();

sock.connect(new InetSocketAddress(host, port));

}


public void read() {

Thread thread = new Thread(new Runnable() {


@Override

public void run() {

// TODO Auto-generated method stub

BufferedInputStream bis = null;

try {

while (true) {


bis = new BufferedInputStream(sock.getInputStream());

byte[] b = new byte[256];

int data = bis.read(b);


if (data != 0) {

System.out.println("\n");

System.out.println(new String(b));

}

}

} catch (IOException e) {

// TODO Auto-generated catch block


System.out.println("client read exception!");

e.printStackTrace();


try {

bis.close();

sock.close();

} catch (IOException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

}

}

});

thread.start();

}


public void chatStart() {

Scanner scan = new Scanner(System.in);

BufferedOutputStream bos=null;

while (true) {

System.out.print("입력>>");

String msg = scan.nextLine();


try {

bos = new BufferedOutputStream(sock.getOutputStream());

bos.write(msg.getBytes("UTF-8"));

bos.flush();

} catch (IOException e) {

// TODO Auto-generated catch block


System.out.println("client write exception!");

try {

bos.close();

sock.close();

break;

} catch (IOException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

e.printStackTrace();

}

}

}


public static void main(String[] args) {

// TODO Auto-generated method stub

Client client = new Client();

try {

client.connect();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

System.out.println("connect exception");

}

client.read();

client.chatStart();

}


}










====> 결과







소켓이 close() 됐을 때의 예외처리는 무엇보다 중요하다.

반드시 예외를 잡고 처리해야한다. 

시간이 없어서 빈약하게 처리했지만, 로직을 작성하는 것보다 메모리 누수 혹은 정확한 처리가 더 중요한 것 같다.




다음은 selector 와  asyncrhronousServerSocket에 대해 마지막으로 알아보자.




https://docs.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousServerSocketChannel.html













+ Recent posts