게시판 만들기 (소켓 통신)

Jane·2023년 3월 6일
0

IT 수업 정리

목록 보기
60/124
  • 소켓 통신 버전을 만들게 되면서... 코드들이 많이 고쳐졌다.
    • Board 패키지 : Post.java, Board.java
    • Socket 패키지
      • MySocketServer.java, MySocketClient.java
        (서버와 클라이언트)
      • WritingThread.java, ListeningThread.java
        (서버와 클라이언트가 주고 받는 것을 쓰고 읽는 동작을 하는 스레드)

Board.java

package Board;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Scanner;

public class Board {
    private Scanner scan;
    private ArrayList<Post> list;
    private PrintWriter writer;

    public Board(OutputStream out) {
        scan = new Scanner(System.in);
        list = new ArrayList<>();
        writer = new PrintWriter(out, true);
    }

    public synchronized void showMenu() {
    	writer.println("---------------------------------");
        writer.println("1 목록 보기 2 글 등록 3 내용 보기 4 글 삭제 0 종료 >> ");
    }

    public synchronized void showList() {
        writer.println("=================================");
        writer.println("번호" + "\t" + "제목" + "\t" + "작성자" + "\t" + "작성일");

        for (Post p : list) {
            String title = truncateTitle(p.getTitle(), 5); // limit title to 10 characters
            writer.println((list.indexOf(p) + 1) + "\t" + title + "\t" + p.getAuthor() + "\t" + p.getDate());
        }

        
        showMenu();
    }
    
    String truncateTitle(String title, int maxLength) {
        if (title.length() > maxLength) {
            title = title.substring(0, maxLength-3) + "...";
        } else {
            title = String.format("%-" + maxLength + "s", title);
        }
        return title;
    }

    public synchronized void addList(String title, String author, String contents) {
        Post post = new Post();
        
        post.setIndex(list.indexOf(post));
        post.setTitle(title);
        post.setAuthor(author);
        post.setParagraph(contents);

        SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy, hh:mm aaa");
        String date = sdf.format(new Date());
        post.setDate(date);

        list.add(post);
        writer.println(author + "의 글이 추가되었습니다.");
        
        showMenu();
    }

    public synchronized void searchList(int num) {
        if (num <= 0 || num > list.size()) {
            writer.println("해당하는 번호에 대한 글이 없습니다.");
            showMenu();
            return;
        }

        Post search = list.get(num - 1);
        writer.println("=================================");
        writer.println(num + "\t" + search.getTitle() + "\t" + search.getAuthor() + "\t" + search.getDate());
        writer.println("---------------------------------");
        writer.println(search.getParagraph());
        
        showMenu();
    }

    public synchronized void delList(int num) {
        if (num <= 0 || num > list.size()) {
            writer.println("해당하는 번호에 대한 글이 없습니다.");
            showMenu();
            return;
        }

        Post del = list.get(num - 1);
        list.remove(del);
        writer.println(num + "번 글이 삭제되었습니다.");
        
        showMenu();
    }
    
    public void showListInServer(){
        System.out.println("=================================");
        System.out.println("번호" + "\t" + "제목" + "\t" + "작성자" + "\t" + "작성일");

        for (Post p : list) {
        	String title = truncateTitle(p.getTitle(), 5);
           System.out.println((list.indexOf(p) + 1) + "\t" + title + "\t" + p.getAuthor() + "\t" + p.getDate());
        }
     }
}
  • 소켓 통신으로 writer에 써지는 관계로, scan이 아닌 writer 용으로 바꾸었다.
  • 클라이언트/서버가 목록창에서 볼 수 있는 길이를 정해두었다.
  • 서버도 목록을 볼 수 있었으면 좋겠다는 피드백을 받아서 서버도 목록을 볼 수 있는 기능을 넣었다. (서로가 읽고 쓸 용도면 writer로 보내고, 자신이 콘솔로 볼 목록이면 System.out을 쓰도록 만들었다.)

MySocketServer.java

package Socket;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import Board.Post;
import Board.Board;

public class MySocketServer extends Thread {
	static Socket socket = null;
	static List<Socket> clients = null;
	boolean idcheck = false;

	public MySocketServer(Socket socket) {
		this.socket = socket; // 유저 socket을 할당
		this.clients = clients;	
	}

	public void run() { // Thread 에서 start() 메소드 사용 시 자동으로 해당 메소드 시작 (Thread별로 개별적 수행)
		try {
			System.out.println("서버 : " + socket.getInetAddress() + " IP의 클라이언트와 연결되었습니다"); // 연결 확인용

			// InputStream - 클라이언트에서 보낸 메세지 읽기
			InputStream input = socket.getInputStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(input));

			// OutputStream - 서버에서 클라이언트로 메세지 보내기
			OutputStream out = socket.getOutputStream();
			PrintWriter writer = new PrintWriter(out, true);
			
			String readValue; // Client에서 보낸 값 저장
			Board board = new Board(out);
			int count = 0;
			
			String author = socket.getInetAddress().toString();

			writer.println("[[게시판 프로그램]]");
			board.showMenu();
			
			while ((readValue = reader.readLine()) != null) { // 클라이언트가 메세지 입력시마다 수행

				out = socket.getOutputStream();
				writer = new PrintWriter(out, true);

				if (readValue.equals("0")) {
					writer.println("종료합니다.");
					System.exit(0);
				} else if (readValue.equals("1")) {
					if (count <= 0) {
						writer.println("등록된 글이 없습니다.");
						board.showMenu();
					} else {
						board.showList();
					}
				} else if (readValue.equals("2")) {

					writer.println("제목 >> ");
					String title = reader.readLine();

					if (!idcheck) {
						writer.println("작성자 >> ");
						String str = reader.readLine();
						author = str;
						idcheck = true;
					} else {
						writer.print("작성자 >> ");
						writer.println(author);
					}

					writer.println("내용 >> ");
					String contents = reader.readLine();

					board.addList(title, author, contents);
					count++;
					board.showListInServer();
				} else if (readValue.equals("3")) {
					if (count <= 0) {
						writer.println("등록된 글이 없습니다.");
						board.showMenu();
					} else {
						writer.println("내용을 볼 글 번호 >> ");
						String str = reader.readLine();
						int searchNum = Integer.parseInt(str);
						board.searchList(searchNum);
					}
				} else if (readValue.equals("4")) {
					if (count <= 0) {
						writer.println("등록된 글이 없습니다.");
						board.showMenu();
					} else {
						writer.println("삭제할 글 번호 >> ");
						String str = reader.readLine();
						int delNum = Integer.parseInt(str);
						board.delList(delNum);
						count--;
						board.showListInServer();
					}
				} else {
					writer.println("선택한 번호의 게시판 기능이 없습니다.");
				}
				
			} // end of while
			


		} catch (Exception e) {
			e.printStackTrace(); // 예외처리
		} finally {
			clients.remove(socket);
			System.out.println("서버 : " + socket.getInetAddress() + " IP의 클라이언트와 연결 종료");
		}
	} // end of run()

	public static void main(String[] args) {
		
		int socketPort = 2400; // 소켓 포트 설정용
		List<Socket> clients = new ArrayList<>();
		try {
			ServerSocket serverSocket = new ServerSocket(socketPort); // 서버 소켓 만들기
			System.out.println("socket : " + socketPort); // 서버 오픈 확인용

			// 소켓 서버가 종료될 때까지 무한루프
			while (true) {
				Socket socketUser = serverSocket.accept(); // 서버에 클라이언트 접속 시
				clients.add(socketUser);
				Thread thd = new MySocketServer(socketUser); // Thread 안에 클라이언트 정보를 담아줌
				thd.start(); // Thread 시작
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

MySocketClient.java

package Socket;

import java.io.IOException;
import java.net.Socket;

public class MySocketClient {
	
	public static void main(String[] args) {
		try {
			Socket socket = new Socket("192.168.0.125", 3333); // 소켓 서버에 접속 
			System.out.println("서버에 접속합니다"); // 접속 확인용
			
			ListeningThread t1 = new ListeningThread(socket); // 서버에서 보낸 메세지 읽는 Thread
			WritingThread t2 = new WritingThread(socket); // 서버로 메세지 보내는 Thread

			t1.start(); // ListeningThread Start
			t2.start(); // WritingThread Start
            
		} catch (IOException e) {
			//e.printStackTrace(); 
		}
	}
}

WritingThread.java

package Socket;

import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class WritingThread extends Thread { // 서버로 메세지 보내는 Thread
	Socket socket = null;
	Scanner scanner = new Scanner(System.in); // 채팅용 Scanner
	
	public WritingThread(Socket socket) { // 생성자
		this.socket = socket; // 받아온 Socket Parameter를 해당 클래스 Socket에 넣기
	}
	
	public void run() {
		try {
			// OutputStream - 클라이언트에서 Server로 메세지 발송 
			OutputStream out = socket.getOutputStream(); // socket의 OutputStream 정보를 OutputStream out에 넣은 뒤
			PrintWriter writer = new PrintWriter(out, true); // PrintWriter에 위 OutputStream을 담아 사용
			
			while(true) { // 무한반복
				writer.println(scanner.nextLine()); // 입력한 메세지 발송
			}
			
		} catch (Exception e) {
			//e.printStackTrace(); // 예외처리
		}
		
		
	}


}

ListeningThread.java

package Socket;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;

public class ListeningThread extends Thread { // 서버에서 보낸 메세지 읽는 Thread
	Socket socket = null;

	public ListeningThread(Socket socket) { // 생성자
		this.socket = socket; // 받아온 Socket Parameter를 해당 클래스 Socket에 넣기
	}
	
	public void run() {
		try {
			// InputStream - Server에서 보낸 메세지를 클라이언트로 가져옴
			InputStream input = socket.getInputStream(); // socket의 InputStream 정보를 InputStream in에 넣은 뒤
			BufferedReader reader = new BufferedReader(new InputStreamReader(input)); // BufferedReader에 위 InputStream을 담아 사용
			
			while(true) { // 무한반복
				System.out.println(reader.readLine());
			}
			
		} catch (Exception e) {
			//e.printStackTrace();
		}
		
	}

}
profile
velog, GitHub, Notion 등에 작업물을 정리하고 있습니다.

0개의 댓글