JAVA ServerSocket Chatting program
Chatting program Basic
서버와 쓰레드를 이용하여 채팅 프로그램을 구현 할 수 있다. 먼저 서버를 구축하는 예제를 보자.
1. Server
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import thread.ServerThread;
public class Main {
public static void main(String[] args) {
Socket clientsocket = null;
List<Socket> list = new ArrayList<Socket>(); // 클라이언트의 소켓정보를 저장
try {
ServerSocket serSocket = new ServerSocket(9000);
while(true) { // accept 상태는 유지하면서 send , recv를 해야함
System.out.println("접속 대기중..."); // client를 기다림
clientsocket = serSocket.accept(); // client가 들어오면 담당 socket
// 접속된 client 의 정보(IP,port) 담고 있음
list.add(clientsocket); // 소켓의 정보들을 list에 저장해준다.
System.out.println("client IP: "+clientsocket.getInetAddress()
+" Port: "+clientsocket.getPort());
new ServerThread(clientsocket, list).start(); // 멈춰줄 필요가 없기 때문에 인스턴스 필요 없다.
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. Server Thread
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.List;
public class ServerThread extends Thread {
Socket clientsocket;
List<Socket> list;
public ServerThread(Socket clientsocket,List<Socket> list) { //소켓과 list를 파라미터로 받는다.
this.clientsocket = clientsocket; //현재 자신의 소켓
this.list = list; // 소켓의 묶음 (다른 IP로 보내주려고)
}
@Override
public void run() {
super.run();
try {
while(true) {
//recv (받는다)
BufferedReader reader =
new BufferedReader(new InputStreamReader(clientsocket.getInputStream()));
String packetStr = reader.readLine(); //실제 전송
System.out.println("클라이언로부터 받은 Packet: "+packetStr);
//send (보내다)
for (int i = 0; i < list.size(); i++) {
Socket soc = list.get(i);
if(clientsocket != soc) { // 자기 자신 이외의 소켓에 전부 전송
PrintWriter pw = new PrintWriter (soc.getOutputStream());
pw.println(packetStr);
pw.flush();
}
}
Thread.sleep(300); // 쓰레드의 어느정도 템포를 준다.
}
}catch(Exception e) {
e.printStackTrace();
}
}
}
서버의 경우 소켓의 정보를 받는 accept은 항상 유지를 해야한다.
recv와 send의 경우 Thread를 통해 한번씩 체크하여 데이터를 송/수신하면 효율적으로 메모리 운영도 가능하며 처리할 수 있다.
3.Client
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Scanner;
import thread.ReadThread;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
InetSocketAddress sockAddr = new InetSocketAddress("192.168.7.72", 9000);
Socket socket = new Socket();
try {
socket.connect(sockAddr, 10000); // 뒤의 timeout 은 밀리세컨으로 1000이 1초
InetAddress inetAddr; // 접속 확인용
if((inetAddr = socket.getInetAddress()) != null){
System.out.println("Server connect success: "+ inetAddr);
}else {
System.out.println("Server connect fail");
}
new ReadThread(socket).start(); // while 문 안에서 계속해서 Thread를 생성해줄 필요 없이 recv만 돌려주면 되어 while 밖에서 실행
while(true) {
System.out.print("전송할 텍스트 입력: ");
String pecket = sc.next();
// send (보내다) //
PrintWriter writer = new PrintWriter(socket.getOutputStream());
writer.println(pecket);
writer.flush(); // 마무리 할때 무조건 기재해 주어야한다.
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
채팅시 클라이언트는 먼저 메세지를 받아야한다. 그래서 우선 Thread를 통해 데이터 수신을체크하고 송신은
언제할지 모르기 때문에 항상 유지를 해야한다. 그래서 while 문안에 배치하여 구현한다.
4. client Thread (readThread)
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
public class ReadThread extends Thread {
Socket socket;
public ReadThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
super.run();
// recv (받는다)
BufferedReader reader;
try {
while(true) {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str = reader.readLine();
System.out.println("Server로 부터 받은 데이터: "+str);
Thread.sleep(300);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}