[Java] 소켓 통신, 서버-클라이언트

nakkim·2022년 3월 2일
0
post-custom-banner
  • 프로세스는 소켓을 통해서 통신
  • 소켓이란 프로그램 간 통신의 Endpoint(연결부)
  • 소켓은 프로토콜, IP주소, 포트번호로 정의
  • 소켓을 이용해서 서버에 연결 요청
  • 소켓은 리눅스에서 파일로 다루어지며 프로세스는 소켓을 사용할때 파일디스크립터를 통해 사용

프로그램

  1. 스레드를 이용해 여러 클라이언트와 연결이 가능하도록 구현
  2. 클라이언트와 연결이 되었으면 연결 정보를 서버에 출력
  3. 클라이언트의 닉네임을 받아서 들어오는 메세지 출력시 구분 가능하도록
  4. bye가 입력되면 연결 종료(bye는 출력 x)
❯ java TCPServer
Waiting connection...
--- Connection Info ---
client address: /127.0.0.1
client port: 64186
my port: 4242
Waiting connection...
--- Connection Info ---
client address: /127.0.0.1
client port: 64187
my port: 4242
Waiting connection...
kim(64186): hi
bye~lee(64187)
kim(64186): asdf
bye~kim(64186)


Server

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

public class TCPServer {

	public final static int SERVER_PORT=4242;
	
	public static void main(String[] args) {
		ServerSocket serverSocket = null; // 클라이언트를 받기 위한 소켓
		
		try {
			serverSocket = new ServerSocket(SERVER_PORT);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		while (true) {
			try {
				System.out.println("Waiting connection...");
				Socket socket = serverSocket.accept(); // 클라이언트 대기(accept()), accept의 리턴값이 실제 데이터를 송수신하는 소켓
				// 서버가 accept 후 넘겨주는 소켓이 클라이언트랑 연결된 소켓임
				// 해당 socket 이용해서 클라이언트와 통신
				
				new ServerThread(socket).start(); // 스레드 생성 후 run() 실행
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

ServerThread

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

class ServerThread extends Thread {
	
	private Socket socket;
	private BufferedReader br;
	private PrintWriter pw;
	private String name;
	
	public ServerThread(Socket socket) {
		this.socket = socket;
        
		// 스레드 실행 시 연결 정보 출력
		System.out.println("--- Connection Info ---");
		System.out.println("client address: " + socket.getInetAddress()); // Client IP
		System.out.println("client port: " + socket.getPort()); // Client Port
		System.out.println("my port: " + socket.getLocalPort()); // Server Port
		
		try {
			// 클라이언트가 전송한 데이터 출력시 사용
			br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			// 클라이언트로 데이터 전송시 사용
			pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void run() {
		pw.println("Hello from Server.");
		pw.println("종료: bye");
		pw.println("닉네임을 입력하세요>");
		pw.flush(); // 버퍼가 다 차기 전까지 내용을 출력하지 않기 때문에 강제로 비워야함
		
		try {
        	// 이름 설정
			name = br.readLine();
			pw.println("set name - " + name);
			pw.flush();
            
            getMessage();
            
            // 연결 종료 시 입출력 스트림 닫고 클라이언트와의 연결 종료
			br.close();
			pw.close();
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("bye~" + name + "(" + socket.getPort() + ")");
	}
    
    public void getMessage() {
		try {
			String received = br.readLine();
            // 수신된 메세지가 null이거나 bye이면 종료
			while (received != null && !received.equals("bye")) {
				System.out.println(name + "(" + socket.getPort() + "): " + received);
				pw.println("Server got message: " + received);
				pw.flush();
				received = this.br.readLine();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
}

Client

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class TCPClient {

	private static final int SERVER_PORT = 4242;

	public static void main(String[] args) {
		String serverIP = "127.0.0.1";
		Scanner sc = new Scanner(System.in);
		try {
			Socket socket = new Socket(serverIP, SERVER_PORT); // 서버의 IP/Port로 연결
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			System.out.println(br.readLine());
			System.out.println(br.readLine());
			System.out.println(br.readLine());
			
			PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
			String input = sc.nextLine(); // 이름 입력
			pw.println(input);
            
			while (!input.equals("bye")) {
				pw.flush();
				System.out.println(br.readLine());
				input = sc.nextLine();
				pw.println(input);
			}
			
			pw.close();
			br.close();
			socket.close();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
profile
nakkim.hashnode.dev로 이사합니다
post-custom-banner

0개의 댓글