채팅만들기

* 서버소켓

package chat;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

public class MySocketServer {

	ServerSocket serverSocket;
	Vector<NewSocketThread> vt;

	public MySocketServer() throws Exception {
		vt = new Vector<>();
		serverSocket = new ServerSocket(3000);

		while (true) {
			Socket socket = serverSocket.accept();
			System.out.println("요청이 들어옴");
			NewSocketThread nt = new NewSocketThread(socket);
			Thread newWorker = new Thread();
			newWorker.start();
			vt.add(nt);
		}
	}

	// 새로운 스레드에게 버퍼를 연결할 수 있게 socket을 전달!
	class NewSocketThread implements Runnable {

		Socket socket;
		BufferedReader br;
		BufferedWriter bw;

		public NewSocketThread(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			try {
				br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

				String msg = "";
				while ((msg = br.readLine()) != null) {
					System.out.println("클라이언트 : " + msg);
					for (NewSocketThread newSocketThread : vt) {
						if (newSocketThread != this) {
							newSocketThread.bw.write(msg + "\n");
							newSocketThread.bw.flush();
						}
						newSocketThread.bw.write(msg + "\n");
						newSocketThread.bw.flush();
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

	public static void main(String[] args) {
		try {
			new MySocketServer();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 

 

서버소켓을 만들어준다.

대기하고 있다가 연결을 계속 받아줘야되기 때문에 while문을 작성한다.

이렇게 작성하면 새로운 소켓이 연결되면 연결될때마다 최근에 연결된 소켓만 가르키고 다른 소켓은 바라보지 않기 때문에(지역변수니까 다시 돌때 사라진다) socket을 보관해야한다.

-> 채팅요청이오면 새로운 스레드가 받아서 연결하고 소켓통신은 다시 요청을 대기해야한다.

새로운 스레드를 만들어준다.

새로운 소켓은 소켓을 알아야 버퍼를 달아서 통신할 수 있는데 소켓이라는 변수가 스택안에 있으니까 사라지기때문에 이 값을 넘겨줘야한다.

while문이 돌때마다 소켓을 넘겨준다.

생성자 생성 후

소켓을 전달

이제 새로운 스레드가 할 일을 지정해줘야한다 -> 채팅!

Buffer 달아줌

최초의 빈 컬렉터를 만들어준다.

만들어진 소켓을 넣기 위해 벡터를 만들어준다.

벡터에 소켓정보를 넣어준다 (모든 소켓의 정보를 벡터가 가지고 있게 된다)

이렇게하면 소켓에 담긴 버퍼에 접근하기가 쉬워진다.

타입은 클래스타입임

문자를 받아서 메세지를 모두에게 뿌려준다.

* flush를 하지 않으면 버퍼가 차야 전송되니까 flush로 버퍼가 차지 않아도 전송될 수 있도록 한다.

* vector 와 array 컬렉션의 차이점

list 밑에 arraylist 와 vector 가 있다.

사용하는 방법과 생긴모양이 똑같지만 한가지만 다르다

데이터에 동시에 접근해서 한명이 데이터를 바꿔버리면 나머지는 이전데이터를 보게된다. 이 경우 임계구역을 설정해서 동시접속을 막을 수 있다.

이때 임계구역을 설정해서 동시접근을 막을때 vector 를 사용한다.

* client

 

package chat;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class MySocketClient {

	Socket socket;

	public MySocketClient() throws Exception {
		socket = new Socket("192.168.0.85", 3000);
		
		ReadThread rt = new ReadThread();
		Thread newWorker = new Thread();
		newWorker.start();
	
		
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

		BufferedReader keyboardln = new BufferedReader(new InputStreamReader(System.in));

		String outputMsg = "";
		while ((outputMsg = keyboardln.readLine()) != null) {
			bw.write(outputMsg + "\n");
			bw.flush();
		}
	}

	class ReadThread implements Runnable {
		@Override
		public void run() {
			try {
				BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				String inputMsg = "";
				while ((inputMsg = br.readLine()) != null) {
					System.out.println("상대방 : " + inputMsg);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	public static void main(String[] args) {
		try {
			new MySocketClient();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

우선 소켓을 연결해준다.

소켓을 연결하고 write와 read 기능을 연결해야하는데,

main 은 키보드 입력을 대기하고있기 때문에

키보드 입력하는 것은 main이, read의 기능은 새로운 스레드가 하게 만들어 줘야한다.

buffer를 달아준다.

읽기 전용 스레드를 만들어준다.

이후 읽기위해 버퍼를 달아주고 try - catch로 감싸준다.

위 세줄을 한줄로 적을 수 있다.

openclose