네트워크

woom·2022년 11월 25일
0

JAVA

목록 보기
18/18
post-thumbnail

🌼 네트워크

  • 네트워크(Network) : 두 대 이상의 컴퓨터에서 값을 송수신하기 위한 기능
  • 인터넷(Internet) : 네트워크 기능을 제공하기 위한 가상의 공간 - 네트워크 관련 약속(정보 공유)

  • 프로토콜(Protocol) : 인터넷을 사용하기 위한 네트워크 관련 통신 규약 ex) IP, TCP, UDP


📕 프로토콜 구조

    1. 네트워크 계층 >
    1. 인터넷 계층(IP) >
    1. 전송 계층(TCP, UDP) >
    1. 응용 계층(FTP, HTTP, SMTP 등)

📌 1. 네트워크 계층

  • 네트워크 관련 장치 (통신 장비에 관련된 약속)
  • 이더넷(Ethernet) : 네트워크에 연결된 기기들이 고유한 매체 접근 제어 주소를 가지고 상호 간에 데이터를 주고 받을 수 있도록 만들어진 근거리 통신망 (컴퓨터에서 사용하기 위한 통신장비)
  • 라우터(Router) : 네트워크 그룹과 네트워크 그룹(나라, 지역)을 연결하기 위한 통신 장비
  • 스위치허브(Switch Hub) : 컴퓨터와 컴퓨터를 연결해주는 장비 (해당 포트(고유의 통신 경로)로만 패킷(데이터 전송 단위) 전송)

📌 2. 인터넷 계층

  • IP(Internet Protocol) : 인터넷을 사용하기 위한 네트워크 주소 (IP주소) 에 대한 통신규약

📌 3. 전송 계층

  • TCP(Transmission Control Protocol) : 연결형 프로토콜(연결 설정 후 통신 가능)로 신뢰할 수 있는 데이타 전송에 대한 통신규약

    • 전송 제어 프로토콜 (소켓을 이용해서 연결하여 패킷으로 묶어 약속한 수만큼 전송)
    • 약속한 수의 패킷을 다 전송받아야 처리 가능
    • ex) 동영상10개 다운받기 전까지 재생 불가
    • 소켓(Socket) 통신 - 1:1 연결
  • UDP(User Datagram Protocol) : 비연결형 프로토콜(연결 설정 없이 통신 가능)로 신뢰할 수 없는 데이타 전송에 대한 통신규약

    • 사용자 데이타그램 프로토콜 (약속 없이 일회성으로 전송)
    • 하나의 패킷도 하나의 데이터로서 처리 가능
    • ex) 동영상 하나만 다운받으면 재생 가능
    • 고속 통신 - 1:Many 연결

📌 4. 응용 계층

  • 전송계층을 기반으로 생성된 다수의 프로토콜 또는 응용 프로그램 포함

📕 네트워크 정보

  • ex) IP주소, Netmask, gateway, DNS주소 등
  • 호스트(Host) : 네트워크를 사용하기 위한 컴퓨터 (프로그램)
  • IP Address : 인터넷을 사용하기 위해 컴퓨터에 부여하는 네트워크 식별자

    • 32Bit 를 이용하여 IP 주소 표현 : 10진수 0~255 범위의 정수값 4개를[ . ]으로 구분하여 표현 ex) 254.128.12.34
      (32Bit=4Byte, 1Byte=8bit → 0~255 범위) - IPV4 프로토콜
    • 128Bit 를 이용하여 IP 주소 표현 : 16진수 0000~FFFF 범위의 정수값 8개로 [ : ]으로 구분하여 표현 ex) 0:0:0:0:0:0:0:0:0
      (128Bit=16Byte, ) - IPV6 프로토콜
    • 공인 IP주소와 사설 IP주소(A : 10.0.0.0~10.255.255.255, B : 172.16.0.0~172.31.255.255, C : 192.168.0.0~192.168.255.255)로 구분
  • Netmask 주소(Netmask Address) : 네트워크 그룹(SubNet)을 표현하기 위한 주소

    • C Class(255.255.255.0) : 라우터를 거치지 않고 256대의 컴퓨터가 데이터를 주고 받을 수 있다.
      → 256대 : 192.X.X.X~233.X.X.X
    • B Class(255.255.0.0) : 256의 2승(65,536) 대의 컴퓨터가 데이터를 주고 받을 있다.
      → 65,536대 : 128.X.X.X~191.X.X.X
    • A Class(255.0.0.0) : 256의 3승(16,777,216) 대의 컴퓨터가 데이터를 주고 받을 있다.
      → 16,777,216 : 0.X.X.X~127.X.X.X
  • Gateway Address : 라우터에 부여된 IP주소
  • DNS Server : 도메인을 IP주소로 변환하는 기능을 제공하는 컴퓨터
  • 도메인(Domain) : 인터넷을 사용하기 위해 네트워크 그룹 또는 호스트에게 부여하는 문자화된 네트워크 식별자

    • 도메인 그룹에 등록되어야 호스트 사용 가능 (도메인 호스트)
  • 포트번호(Port Number) : 네트워크를 이용하여 데이타를 전송하기 위한 고유의 통신 경로

    • 네트워크는 반드시 0 ~ 65,535 범위의 포트 중 하나를 선택하여 데이타 전송
    • 0 ~ 1023 : Well-Known Port로 시스템에서 사용하기 위해 약속되어진 포트
    • ex. HTTP : 80, HTTPS : 443 ( HTTP 웹서비스를 통해 값을 전달 / HTTPS(security) 암호화해서 전달 SMTP(메일발신) : 25, POP3(메일수신) :110 등
    • 1024 ~ 49,151 : 네트워크 프로그램 작성시 사용 가능한 포트
    • 49,152 ~ 65,535 : 일시적으로 사용하는 임시 포트 (Private Port)
  • 패킷(Packet) : 네트워크에서 데이타를 전송하기 위한 단위

    • Java에서는 byte 배열로 표현 가능 (객체 직렬화 필요)
  • 방화벽(Firewall) : 네트워크를 이용한 접속 및 데이터 전송 차단 또는 허용을 위해 사용하는 시스템


📙 InetAddress

  • 네트워크 정보(IP Address와 HostName)를 저장하기 위한 클래스
  • InetAddress.getLocalHost() : 로컬(자기자신) 컴퓨터의 네트워크 정보가 저장된 InetAddress 객체를 반환하는 메소드

    • UnknownHostException 발생(일반 예외) : 네트워크 컴퓨터 이름(HostName)의 컴퓨터를 검색할 수 없는 경우 발생되는 예외
    • 로컬 컴퓨터의 이더넷에는 기본적으로 [127.0.0.1]의 IP Address와 [localhost] 이름으로 HostName 설정
  • InetAddress.toString() : InetAddress 객체에 저장된 네트워크 정보를 문자열로 반환하는 메소드

  • InetAddress.getHostName() : InetAddress 객체에 저장된 네트워크 정보에서 HostName을 문자열로 반환하는 메소드

  • InetAddress.getHostAddress() : InetAddress 객체에 저장된 네트워크 정보에서 IP Address을 문자열로 반환하는 메소드

  • InetAddress.getByName(String host) : 전달받은 컴퓨터 이름에 대한 네트워크 정보가 저장된 InetAddress 객체를 반환하는 메소드

  • InetAddress.getAllByName(String host) : 전달받은 컴퓨터 이름에 대한 모든 네트워크 정보가 저장된 InetAddress 객체 배열을 반환하는 메소드


🐣 예제

public class InetAddressApp {
	public static void main(String[] args) throws UnknownHostException {
		InetAddress myComputer=InetAddress.getLocalHost();

		System.out.println(myComputer);//DESKTOP-Q0AEAH6/192.168.13.9
		System.out.println(myComputer.getHostName());//DESKTOP-Q0AEAH6
		System.out.println(myComputer.getHostAddress());//192.168.13.9
		

		//InetAddress.getByName(String host) : InetAddress 객체를 반환
		InetAddress itwill=InetAddress.getByName("www.itwill.xyz");
		System.out.println("IP Address = "+itwill.getHostAddress());
		

		//InetAddress.getAllByName(String host) : InetAddress 객체 배열을 반환
		InetAddress[] naver=InetAddress.getAllByName("www.naver.com");
		
		for(InetAddress address:naver) {
			System.out.println("IP Address = "+address.getHostAddress());
		}}}





📙 TCP 프로그램 작성-1

  • TCP 프로그램 작성 : ServerSocket 클래스와 Socket 클래스를 이용하여 작성
    • 서버와 클라이언트가 소켓을 사용하여 1:1로 연결되어 데이타를 송수신하는 네트워크 프로그램
  • 서버(Server) : 외부의 컴퓨터(클라이언트)가 접속할 수 있는 환경과 서비스를 제공하기 위한 컴퓨터

    • 대표적인 웹서버 : 네이버, 다음
    • ServerSocket 클래스를 사용하여 서버 프로그램 작성
  • ServerSocket : 네트워크에서 서버 프로그램을 만들기 위해 사용하는 클래스

    • ServerSocket(int port) : 포트번호를 전달받아 ServerSocket 객체를 생성하는 생성자
    • ServerSocket 객체를 생성하여 클라이언트가 접속할 수 있는 환경 제공
    • 전달받은 포트번호를 이미 다른 네트워크 프로그램에서 사용중인 경우 IOException 발생
  • ServerSocket.close() : ServerSocket 객체를 제거하는 메소드

    • 클라이언트가 접속할 수 있는 환경 소멸
  • 클라이언트(Client) : 서버에 접속하여 서비스를 제공받을 수 있는 컴퓨터 (서버 이용자)

    • Socket 클래스를 사용하여 클라이언트 프로그램 작성
  • cmd에서 netstat -na : 네트워크에서 사용중인지 확인 가능


🐣 예제 (포트번호 검색)

  • ServerSocket 클래스를 사용하여 사용 가능한 포트번호를 검색하는 프로그램
public class ServerSocketApp {
	public static void main(String[] args) {
		for(int i=2000;i<=9000;i+=1000) {
			try {
				ServerSocket serverSocket=new ServerSocket(i);
                //포트번호i 전달받아 객체 생성
				
				System.out.println(i+"번 포트는 프로그램에서 사용 가능.");
				
				serverSocket.close();
			} catch (IOException e) {
				System.out.println("[에러]"+i+"번 포트는 이미 사용중."); }}}}
                




📙 TCP 프로그램 (output)

  • 네트워크 프로그램 : 두 대 이상의 컴퓨터에서 값을 주고 받는 프로그램

  • NTP(Network Time Protocol) Server : 날짜와 시간을 제공하는 서버 컴퓨터

  • ServerSocket.toString() : ServerSocket 객체에 저장된 접속 관련 정보를 문자열로 반환하는 메소드

  • ServerSocket.accept() : 클라이언트의 접속을 기다리는 메소

    • 클라이언트가 접속되기 전까지 스레드 일시 중지
    • 클라이언트가 접속하면 클라이언트의 소켓과 연결될 소켓(Socket 객체)를 생성하여 반환하고 스레드 실행
  • socket.getOutputStream() : Socket 객체의 출력스트림(OutputStream 객체)을 반환하는 메소드

  • Socket.getInetAddress() : 소켓으로 연결된 외부 컴퓨터의 네트워크 정보(InetAddress 객체)를 반환하는 메소드

  • tcp프로그램에서는 서버(accept메소드)가 먼저 샐행되어야 클라이언트가 접속 가능

  • accept() 메소드 실행시 서버 프로그램에 다수의 클라이언트 접속을 허용하도록 무한루프 사용

    • 무한루프 안하면 하나의 클라이언트에만 서버 제공되므로 무한반복을 통해서 다수의 클라이언트 접속을 허용

🐣 예제 (날짜와 시간 전달)

  • 접속된 클라이언트에게 서버 컴퓨터의 현재 날짜와 시간을 전달하는 서버 프로그램
public class TimeServerApp {
	public static void main(String[] args) {
		ServerSocket ntpServer=null;
		
		try {
			//포트(2000)를 활성화 시켜 클라이언트가 접속할 수 있는 환경 제공
			ntpServer=new ServerSocket(2000);//ServerSocket 객체 생성 
			
			System.out.println(ntpServer);//: 포트가 2000인 ServerSocket주소
			System.out.println("[메세지]NTP Server Running...");
                 
			while(true) {
				Socket socket=ntpServer.accept();//Socket 객체 생성
				
				System.out.println("socket = "+socket);
				
				OutputStream out=socket.getOutputStream();
				
				//OutputStream객체를 전달받아 객체 전달이 가능한
                //ObjectOutputStream객체로 출력스트림 확장
				ObjectOutputStream stream=new ObjectOutputStream(out); 
				
				//시스템의 현재 날짜와 시간이 저장된 Date 객체 생성 
				Date now=new Date();
				
				//출력스트림을 이용하여 Date 객체 전달(client에게 날짜와 시간 전송)
				stream.writeObject(now);//출력스트림으로 객체 전달
				
				new ObjectOutputStream(socket.getOutputStream()).writeObject(new Date());
								
				//로그 처리 - 기록
				System.out.println("[정보]클라이언트["+socket.getInetAddress()
					.getHostAddress()+"]에게 날짜와 시간을 제공 하였습니다.");
				
				//클라이언트와의 연결 해제
				socket.close();
			}
		} catch (IOException e) {
			System.out.println("[에러]서버 네트워크에 문제가 발생 하였습니다."); }}}





📙 TCP 프로그램 (input)

  • Socket : TCP 프로그램에서 다른 컴퓨터와 연결을 위한 정보를 저장하기 위한 클래스

  • Socket(String host, int port) : 호스트(IP Address)와 포트를 전달하여 서버 컴퓨터에 접속한 Socket 객체를 생성하는 생성자

    • UnknownHostException 또는 IOException 발생 (일반 예외이므로 반드시 예외 처리)
    • Socket 객체에는 연결된 컴퓨터에 정보를 보내거나 받을 수 있는 입력스트림 또는 출력스트림이 자동 생성되어 제공
  • Socket.toString() : Socket 객체에 저장된 접속 관련 정보(접속 호스트 및 포트와 로컬 호스트 및 포트)을 문자열로 반환하는 메소드

  • Socket.getInputStream() : Socket 객체의 입력스트림(InputStream 객체)을 반환하는 메소드

  • Socket.close() : Socket 객체를 제거하는 메소드 - 접속해제


🐣 예제 (날짜와 시간 출력)

  • NTP Server에 접속하여 서버에서 보내온 날짜와 시간을 얻어와 출력하는 클라이언트 프로그램

public class TimeClientApp {
	public static void main(String[] args) throws ClassNotFoundException {
		try {
			Socket socket=new Socket("192.168.13.8", 2000);
            //IP주소와 port가 정해진 socket 객체(서버) 생성
			System.out.println("socket = "+socket);

			InputStream in=socket.getInputStream();
			 
			//InputStream 객체를 전달받아 객체를 얻어올 수 있는 
            //ObjectInputStream 객체로 입력스트림 확장
			ObjectInputStream stream=new ObjectInputStream(in);
			
			//입력스트림에서 Date 객체를 얻어와 저장
			Date date=(Date)stream.readObject();
			
			//Date 객체에 저장된 날짜와 시간을 원하는 형식의 문자열로 변환하여 출력
			System.out.println("서버에서 제공한 날짜와 시간 = "+new
            SimpleDateFormat("yyyy년 MM월 dd일 E요일 HH시 mm분 dd일").format(date));
			
			//Socket.close() : Socket 객체를 제거하는 메소드 - 접속해제
			socket.close();
		} catch (UnknownHostException e) {
			System.out.println("[에러]서버 컴퓨터를 찾을 수 없습니다.");
		} catch (IOException e) {
			System.out.println("[에러]서버에 접속할 수 없습니다."); }}}





🐣 예제 (메시지 출력)

  • 클라이언트에서 보내온 메세지를 얻어와 출력하는 서버 프로그램

public class EchoServerApp {
	public static void main(String[] args) {
		ServerSocket echoServer=null;
		
		try {
			echoServer=new ServerSocket(3000);
			System.out.println("[메세제]Echo Server Running...");
			
			while(true) {
				Socket socket=echoServer.accept();
				
				//Socket 객체의 입력스트림을 반환받아 대량의 문자데이타를
                //읽을 수 있는 입력스트림으로 확장
				BufferedReader in=
                new BufferedReader(new InputStreamReader(socket.getInputStream()));
				
				//클라이언트에서 보내온 메세지를 입력스트림을 이용하여 얻어와 출력
				// → 클라이언트에서 메세지를 보내기 전까지 스레드 일시 중지
				System.out.println("["+socket.getInetAddress().getHostAddress()
						+"]님이 보내온 메세지 = "+in.readLine());
				
				socket.close();
			}
		} catch (IOException e) {
			System.out.println("[에러]서버 네트워크에 문제가 발생 하였습니다."); }}}





🐣 예제 (메시지 전달)

  • PrintWriter.println(Object o) : 모든 형식의 값을 문자열로 처리하여 출력스트림으로 전달하는 메소드

  • 키보드로 메세지를 입력받아 접속 서버에 전달하는 클라이언트 프로그램


public class EchoClientApp {
	public static void main(String[] args) throws IOException {
		//대량의 문자데이타를 입력받을 수 있도록 키보드 입력스트림 확장
		BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
		
		System.out.print("전달 메세지 입력 >> ");
		String message=in.readLine();
		
		try {
			//Socket 객체 생성 - 서버 접속
			Socket socket=new Socket("192.168.13.8", 3000);
			
			
			//소켓의 출력스트림을 반환받아 대량의 문자데이타를
            //전달할 수 있는 출력스트림으로 확장
			BufferedWriter out=
            new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
			
			//출력스트림을 이용하여 서버에 문자열(메세지) 전달 
			//문자데이타를 출력버퍼에 저장, 일정크기가 되면 출력스트림으로 전달
			out.write(message);
			//출력버퍼에 존재하는 문자데이타를 출력스트림으로 전달
			out.flush();
			
			
			//소켓의 출력스트림을 반환받아 모든 형식의 값을 전달할 수 있는 출력스트림으로 확장
			PrintWriter out=new PrintWriter(socket.getOutputStream());
			
			out.println(message);
			out.flush();
			
			//접속 해제
			socket.close();
		} catch (IOException e) {
			System.out.println("[에러]서버에 접속할 수 없습니다."); }}}





📒 UDP 프로그램

  • DatagramSocket 클래스와 DatagramPacket 클래스를 이용하여 작성
    • 정보를 전달하는 컴퓨터와 정보를 얻어오는 컴퓨터로 구분하여 처리
  • DatagramSocket 클래스 : 다른 컴퓨터에 연결하기 위한 정보를 저장한 클래스

  • String.getBytes() : String 객체에 저장된 문자열을 byte 배열(원시데이타의 모임)로 변환하여 반환하는 메소드

  • DatagramPacket 클래스 : 연결 컴퓨터에게 보낼 패킷정보를 저장하기 위한 클래스

  • DatagramPacket(byte[] buf, int length, InetAddress address, int port) : DatagramPacket 객체를 생성하기 위한 생성자

    • buf : 전달값(원시데이타), length : 패킷크기, address : 연결 컴퓨터의 네트워크 정보, port : 연결 컴퓨터의 포트번호
  • DatagramSocket.send(DatagramPacket packet) : 패킷을 전달하는 메소드

  • DatagramSocket.close() : DatagramSocket 객체를 제거하는 메소드

  • DatagramSocket.receive(DatagramPacket packet) : 연결 컴퓨터에서 보내온 패킷을 얻어와 저장하는 메소드

    • 패킷을 받기 전까지 스레드 일시 중지

🐣 예제 (메세지 전달)

  • 키보드로 메세지를 입력받아 다른 컴퓨터에게 전달하는 UDP 기반의 네트워크 프로그램
public class MessageSendApp {
	public static void main(String[] args) throws IOException {
		//대량의 문자데이타를 입력받을 수 있는 키보드 입력스트림으로 확장
		BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
		
		System.out.print("전달 메세지 입력 >> ");
		String message=in.readLine();
		
		DatagramSocket socket=new DatagramSocket();
		
		//연결될 컴퓨터의 네트워크 정보를 저장한 InetAddress 객체 생성
		InetAddress address=InetAddress.getByName("192.168.13.8");
		
		byte[] data=message.getBytes();	//전달값을 원시데이타로 변환
		
		DatagramPacket packet=new DatagramPacket(data, data.length, address, 4000);
		
		socket.send(packet);//패킷을 전달하는 메소드
		
		socket.close();	//DatagramSocket 객체를 제거
		
		System.out.println("[결과]연결 컴퓨터에게 메세지를 보냈습니다."); }}





🐣 예제 (메세지 출력)

  • 다른 컴퓨터에서 보내온 메세지를 얻어와 출력하는 UDP 기반의 네트워크 프로그램
public class MessageReceiveApp {
	public static void main(String[] args) throws IOException {
		//DatagramSocket 객체 생성 
		// → 포트를 활성화하여 다른 컴퓨터에서 보내온 패킷을 받을 수 있는 환경 제공
		DatagramSocket socket=new DatagramSocket(4000);
		
		//전달받은 패킷에 저장된 값(메세지)를 저장하기 위한 byte 배열 선언 
		byte[] data=new byte[1024];
		
		//연결 컴퓨터에서 보내온 패킷을 저장하기 위한 DatagramPacket 객체 생성
		//  → DatagramPacket(byte[] buf, int length) 생성자 이용
		DatagramPacket packet=new DatagramPacket(data, data.length);
		
		System.out.println("메세지 수신중...");
		
		//DatagramSocket.receive(DatagramPacket packet) : 연결 컴퓨터에서 보내온 패킷을 
		//얻어와 저장하는 메소드 - 패킷을 받기 전까지 스레드 일시 중지
		socket.receive(packet);
		
		//byte 배열에 저장된 원시데이타를 문자열로 변환하여 저장
		String message=new String(data);
		
		System.out.println("[결과]메세지 = "+message);
		
		socket.close(); }}





🎀 연습문제 (채팅-server)

  • 채팅 서버 프로그램 (다중 스레드 프로그램)
    • 클라이언트에서 보내온 메세지를 전달받아 접속된 모든 클라이언트에게 전달하는 기능 제공
    • 클라이언트와 연결과 소켓은 새로운 스레드를 생성하여 독립적으로 입출력되도록 작성
public class ChatServerApp {
	//접속된 모든 클라이언트의 소켓정보를 저장하기 위한 콜렉션 필드
	private List<SocketThread> clientList=null;
	
	public ChatServerApp() {
		ServerSocket chatServer=null;
		
		try {
			chatServer=new ServerSocket(5000);
			System.out.println("[메세지]채팅 서버 동작 중...");
			
			clientList=new ArrayList<SocketThread>();
			
			while(true) {
				try {
					//클라이언트가 접속되면 클라이언트와 연결된 Socket 객체를 반환받아 저장
					Socket client=chatServer.accept();
					
					System.out.println("[접속로그]"+client.getInetAddress().getHostAddress()
							+"의 컴퓨터에서 접속 하였습니다.");
					
					//Thread 클래스를 상속받은 자식클래스로 객체 생성 - Thread 객체 생성
					SocketThread socketThread=new SocketThread(client);
					
					//콜렉션 필드에 저장된 List 객체에 요소(SocketThread 객체)를 추가하여 저장
					clientList.add(socketThread);
					
					//Thread 객체로 새로운 스레드를 생성하여 run() 메소드의 명령 실행
					socketThread.start();
				} catch (IOException e) {
					System.out.println("클라이언트의 접속 관련 문제가 발생 되었습니다.");
				}
			}
		} catch (IOException e) {
			System.out.println("[에러로그]서버가 정상적으로 동작되지 않습니다.");
		}
	}
	
	public static void main(String[] args) {
		new ChatServerApp();
	}
	
	//현재 서버에 접속된 모든 클라이언트에게 메세지를 전달하는 메소드
	public void sendMessage(String message) {
		//List 객체에 저장된 요소(SocketThread 객체)를 하나씩 제공받아 반복 처리
		for(SocketThread client:clientList) {
			//SocketThread 객체의 출력스트림을 이용하여 클라이언트에게 메세지 전달
			client.out.println(message);
		}
	}
	
	//클라이언트와 연결된 소켓을 이용하여 입출력 기능을 제공하기 위한 클래스
	// → 독립적인 입력 또는 출력 기능을 제공하기 위해 새로운 스레드를 생성하여 실행되도록 설정
	public class SocketThread extends Thread {
		//클라이언트의 소켓과 연결된 Socket 객체를 저장하기 위한 필드 
		private Socket socket;
		
		//클라이언트에서 보내온 메세지를 읽기 위한 입력스트림을 저장하기 위한 필드
		private BufferedReader in;
		
		//클라이언트로 메세지 보내기 위한 출력스트림을 저장하기 위한 필드
		private PrintWriter out;

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

		//새로운 스레드가 실행하기 위한 명령 작성
		// → 클라이언트의 메세지를 전달받아 모든 접속 클라이언트에게 전달하는 명령 실행
		@Override
		public void run() {
			String aliasName="";//클라이언트의 대화명을 저장하기 위한 변수 선언
			
			try {
				//클라이언트와 연결된 소켓의 입력스트림을 반환받아 대량의 문자데이타를 
				//읽을 수 있는 입력스트림으로 확장 
				in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
				
				//클라이언트와 연결된 소켓의 출력스트림을 반환받아 모든 형식의 값을 문자열로
				//전달할 수 있는 출력스트림으로 확장 
				//out=new PrintWriter(socket.getOutputStream());//출력버퍼 사용
				
				//PrintWriter(OutputStream out, boolean autoFlush) : autoFlush 매개변수에
				//[true]를 전달할 경우 출력버퍼를 사용하지 않고 출력스트림에 값을 직접 전달
				out=new PrintWriter(socket.getOutputStream(), true);
				
				//클라이언트에서 보내온 대화명을 얻어와 변수에 저장
				// → 클라이언트에서 대화명을 입력받아 전달할 때까지 스레드 일시 중지
				aliasName=in.readLine();
				
				//현재 접속된 모든 클라이언트에게 입장 메세지를 전달
				sendMessage("["+aliasName+"]님이 입장 하였습니다.");
				
				//클라이언트에서 보내온 메세지를 전달받아 현재 접속된 모든 클라이언트에게 전달
				// → 클라이언트가 접속을 종료하기 전까지 반복 처리
				// → 클라이언트가 접속을 종료하면 클라이언트와 연결된 소켓의 입력스트림과 
				//출력스트림에 제거되어 IOException 발생
				while(true) {
					sendMessage("["+aliasName+"]"+in.readLine());
				}
			} catch (IOException e) {
				//클라이언트가 접속을 종료한 경우 실행될 명령 작성
				//콜렉션 필드에 저장된 List 객체에서 접속 종료된 client의 소켓정보(SocketThread)삭제
				// → 현재 접속중인 모든 클라이언트에게 퇴장 메세지 전달 
				clientList.remove(this);//this 키워드로 현재 사용중인 SocketThread 객체 표현
				sendMessage("["+aliasName+"]님이 퇴장 하였습니다.");
				
				System.out.println("[해제로그]"+socket.getInetAddress().getHostAddress()
						+"의 컴퓨터에서 접속을 종료 하였습니다."); }}}}





🎀 연습문제 (채팅-client)

  • 채팅 클라이언트 프로그램 (Swing)
    • 서버에서 보내온 메세지를 전달받아 JTextArea 컴퍼넌트에 출력 (무한루프)
    • JTextField 컴퍼넌트에서 입력한 메세지를 서버에 전달 (이벤트 처리 메소드)
public class ChatClientApp extends JFrame implements ActionListener {
	private static final long serialVersionUID = 1L;

	private JTextArea area;//출력 컴퍼넌트
	private JTextField field;//입력 컴퍼넌트
	
	//서버의 소켓과 연결된 소켓정보를 저장하기 위한 필드
	private Socket socket;
	
	//서버에서 보내온 메세지를 읽기 위한 입력스트림을 저장하기 위한 필드
	private BufferedReader in;
	
	//서버에서 메세지를 보내기 위한 출력스트림을 저장하기 위한 필드
	private PrintWriter out;
	
	//대화명을 저장하기 위한 필드
	private String aliasName;
	
	public ChatClientApp(String title) {
		super(title);
		
		area=new JTextArea();
		field=new JTextField();
		
		JScrollPane pane=new JScrollPane(area);
		
		getContentPane().add(pane, BorderLayout.CENTER);
		getContentPane().add(field, BorderLayout.SOUTH);
		
		area.setFont(new Font("굴림체", Font.BOLD, 20));
		field.setFont(new Font("굴림체", Font.BOLD, 20));
		
		area.setFocusable(false);
		
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setBounds(700, 200, 400, 500);
		setVisible(true);
		
		//JTextField 컴퍼넌트에서 이벤트가 발생될 경우 실행될 이벤트 처리 객체 등록
		// → 클라이언트가 메세지를 입력한 경우 실행될 명령을 이벤트 처리 메소드에 작성
		field.addActionListener(this);
		
		try {
			//Socket 객체 생성 - 채팅 서버에 접속
			socket=new Socket("192.168.13.31", 5000);
			
			//서버와 연결된 소켓의 입력스트림을 반환받아 대량의 문자데이타를 읽을 수
			//있는 입력스트림으로 확장 
			in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
			
			//서버와 연결된 소켓의 출력스트림을 반환받아 모든 형식의 값을 문자열로 전달할 수
			//있는 출력스트림으로 확장 
			out=new PrintWriter(socket.getOutputStream(), true);
		} catch (IOException e) {
			JOptionPane.showMessageDialog(this, "서버에 접속할 수 없습니다.",
            "접속오류", JOptionPane.ERROR_MESSAGE);
			System.exit(0);
		}
		
		//대화명을 입력받아 필드에 저장
		// → 정상적인 대화명이 입력되도록 무한루프 이용
		while(true) {
			//JOptionPane.showInputDialog(Component parent, String message,
            //String title, int messageType)
			// → 입력 다이얼로그를 보여주는 메소드 - 입력값을 문자열로 반환
			aliasName=JOptionPane.showInputDialog(this,"대화명을 입력해 주세요.",
            "대화명 입력", JOptionPane.QUESTION_MESSAGE);
			
			String regEx="^[가-힣]{2,6}$";
			
			//정상적인 대화명을 입력한 경우 반복문 종료
			if(Pattern.matches(regEx, aliasName)) break;
			
			JOptionPane.showMessageDialog(this, "정상적인 대화명을 입력해 주세요.",
            "입력오류", JOptionPane.ERROR_MESSAGE);
		}
		
		//서버에 대화명 전달
		out.println(aliasName);
		
		//서버에서 보내온 메세지를 전달받아 JTextArea 컴퍼넌트에 추가하여 출력 - 무한루프
		while(true) {
			try {
				area.append(in.readLine()+"\n");
				
				//JTextArea 컴퍼넌트의 스크롤을 맨 아래로 이동 처리
				area.setCaretPosition(area.getText().length());
			} catch (IOException e) {
				JOptionPane.showMessageDialog(this, "서버와 연결이 끊어졌습니다.",
                "접속오류", JOptionPane.ERROR_MESSAGE);
				System.exit(0);
			}
		}
	}
	
	public static void main(String[] args) {
		new ChatClientApp("자바채팅");
	}

	//이벤트 처리 메소드에서는 JTextField 컴퍼넌트의 입력값(메세지)을 반환받아
    //서버에 전달하는 명령 작성
	@Override
	public void actionPerformed(ActionEvent e) {
		//JTextField 컴퍼넌트의 입력값을 반환받아 저장
		String message=field.getText();
		
		if(!message.equals("")) {//입력메세지가 존재하는 경우
			out.println(message);//서버에 메세지 전달
			field.setText("");//JTextField 컴퍼넌트 초기화 }}}





profile
Study Log 📂

0개의 댓글

관련 채용 정보