■ 응집도와 결합도

https://medium.com/@jang.wangsu/%EC%84%A4%EA%B3%84-%EC%9A%A9%EC%96%B4-%EC%9D%91%EC%A7%91%EB%8F%84%EC%99%80-%EA%B2%B0%ED%95%A9%EB%8F%84-b5e2b7b210ff

 

[설계 용어] 응집도와 결합도

High Cohesion, Low Coupling, 응집도와 결합도 라는 설계관련 용어는 프로그래밍에 익숙하지 않은 사람들에게는 쉽게 익숙해지기가 처음에는 어려울 것 같아요.

medium.com

- 자바 스터디 그룹에서 매일 배운 내용을 돌아가며 요약하고 발표하고 있다.

- 최근 인터페이스를 다루었었는데, 그 때 응집도와 결합도에 대한 이야기가 나왔다. 정확히 무슨 말인지 이해가 가지 않았는데, 오늘 이에 대해 다시 이야기를 나누면서 자료를 찾아보니 이해가 조금 가게 된 것 같다.

 

[ 응집도와 결합도는 설계 용어이다 ]

- 모듈이란 클래스나 패키지, 라이브러리와 같이 프로그램을 구성하는 임의의 요소를 말한다.

- 좋은 설계는 높은 응집도와 낮은 결합도를 갖도록 모듈을 구성하는 것이다.

 

[1] 응집도란?

- 응집도는 쉽게 생각했을 때, "모듈 한 곳에 기능을 잘 모아놓은 것"인 것 같다.

- 위 링크에서는, 

  (1) 모듈이 하나의 목적을 수행하는 요소들간의 연관성 척도

  (2) 모듈 내부의 기능적인 응집 정도를 나타낸다.

  라고 설명을 해주었다.

 

[2] 결합도란?

- 결합도는 쉽게 생각했을 때, "모듈 하나의 수정이 다른 모듈에 영향을 미치는 정도"인 것 같다.

- 위 링크에서는, 

  (1) 다른 모듈과의 의존성의 정도

  (2) 모듈과 모듈 간의 상호 결합 정도

  라고 설명을 해주었다.

 

■ 컴파일러 버전 바꾸기

- [프로젝트] - 오른쪽마우스 - [Properties] - [Java Compiler] 

- 체크를 풀어주고, 버전을 변경한다.

 

■ Facet도 같이 바꿔야한다.

http://gostop.hangame.com/gameGuide/gssudda/guide_gssudda01_03.html

package _07_객체지향프로그래밍2;

class SutdaDeck{
	final int CARD_NUM = 20;
	SutdaCard[] cards = new SutdaCard[CARD_NUM];
	
	SutdaDeck() {
		/*
		 * 배열 SutdaCard초기화
		 * 
		 */
	}
} 

class SutdaCard{
	int num;
	boolean isKwang;
	
	SutdaCard(){
		this(1,true);
	}
	
	SutdaCard(int num, boolean isKwang){
		this.num = num;
		this.isKwang = isKwang;
	}
	
	@Override
	public String toString() {
		return num + (isKwang? "K":"");
	}
	
}

public class EX7_1 {
	public static void main(String[] args) {
		SutdaDeck deck = new SutdaDeck();
		for(int i=0; i < deck.cards.length;i++)
			System.out.print(deck.cards[i]+",");
	}

}

>> 결과

1K,2,3K,4,5,6,7,8K,9,10,1,2,3,4,5,6,7,8,9,10,
더보기

[나의 풀이]

SutdaDeck() {
    //1~20까지 1-10순으로 숫자 초기화 **숫자가 1,3,8의 경우 둘 중 하나는 광
    int num = 1;
    for (int i = 0; i < CARD_NUM; i++) {
        if (i == 10) num = 1; 
        if (i+1 == 1 || i+1 == 3 || i+1 == 8) {
            cards[i] = new SutdaCard(num++,true);
        }else {
            cards[i] = new SutdaCard(num++,false);
        }
    }//end for
}//SutdaDeck()

[남궁성님 풀이]

for (int i = 0; i < cards.length; i++){
    //숫자를 넣어줄 변수
    int num = i % 10 + 1;  //i가 0일때 > 1, i가 1일때 >2...i가 10일때 > 1
    boolean isKwang = (i < 10) && (num == 1 || num == 3 || num == 8);
    
    cards[i] = new SutdaCard(num, isKwang);
}

엄청나게 간결해진 코드. 객체 생성자의 매개변수에 연산식을 줌으로써 코드를 확 줄였다.

▶ 내가 잡고 가야할 점 : 복잡한 조건문을 쓰기 보다, 변수 자체에 연산식을 사용하는 법을 먼저 고려해보자.

 

package _07_객체지향프로그래밍2;

class SutdaDeck2{
	final int CARD_NUM = 20;
	SutdaCard2[] cards = new SutdaCard2[CARD_NUM];
	
	SutdaDeck2() {
		
		//문제 7_1 정답

	}//SutdaDeck()
    
    //(1) 정의된 세개의 메서드 작성
} 

class SutdaCard2{
	int num;
	boolean isKwang;
	
	SutdaCard2(){
		this(1,true);
	}
	
	SutdaCard2(int num, boolean isKwang){
		this.num = num;
		this.isKwang = isKwang;
	}
	
	@Override
	public String toString() {
		return num + (isKwang? "K":"");
	}
	
}

public class EX7_2 {
	public static void main(String[] args) {
		SutdaDeck deck = new SutdaDeck();
		
		System.out.println(deck.pick(0));
		System.out.println(deck.pick());
		deck.shuffle();
		
		for(int i=0; i < deck.cards.length;i++)
			
		System.out.print(deck.cards[i]+",");
		System.out.println();
		System.out.println(deck.pick(0));
	}

}

>> 결과

1K
7
2,6,10,1K,7,3,10,5,7,8,5,1,2,9,6,9,4,8K,4,3K,
2
더보기

[나의 풀이]

void shuffle() {
    SutdaCard2 tmp;
    int ran = 0;
    for (int i = 0; i < cards.length; i++) {
        ran = (int)(Math.random()*cards.length)+1;
        tmp = cards[i];
        cards[i] = cards[ran];
        cards[ran] = tmp;
    }
}

SutdaCard2 pick(int index) {
    //배열 cards에서 지정된 위치의 SutdaCard를 반환한다
    return cards[index];
}

SutdaCard2 pick() {
    //배열 cards에서 임의의 위치의 SutdaCard를 반환 
    int ran = (int)(Math.random()*cards.length)+1;
    return cards[ran];
}

[남궁성님 풀이]

void shuffle() {
    for(int i=0; i<cards.length;i++) {
        int j = (int)(Math.random()*cards.length);
        // cards[i] cards[j] . 와 의 값을 서로 바꾼다
        SutdaCard tmp = cards[i];
        cards[i] = cards[j];
        cards[j] = tmp;
    }
}

SutdaCard pick(int index) {
    if(index < 0 || index >= CARD_NUM) // index의 유효성을 검사한다
        return null;
        return cards[index];
}

SutdaCard pick() {
    int index = (int)(Math.random()*cards.length);
    return pick(index); // pick(int index)를 호출한다
}

매개변수의 유효성을 고려하지 않았다! 오마이갓 (잊어버림)

▶ index가 0보다 작거나 또는 배열의 범위를 넣어가버린다면 예외(ArrayIndexOutOfBounds)가 발생할 거다.

▶ 항상 메소드를 작성할 때는 수식을 쓰기 전에 매개변수의 유효성을 고려하자! (<<제발 ㅠ)

더보기

[나의 답변]

오버라이딩은 부모로부터 상속받은 메소드를 자식이 새롭게 재정의 하는 것을 말한다.

오버라이딩은 다형성과도 연관이 있는데,

일반 클래스, 추상 클래스, 인터페이스로부터 상속받은 메소드를 자식이 오버라이딩할 수 있으면,

(1) 불필요한 코드의 중복을 줄일 수 있고

(2) 개발자가 다수의 메소드를 생성하고 익히지 않고도 단순히 기존 메소드를 재정의함으로 원하는 기능을 다향하게 구현할 수 있다.

 

[남궁성님 답변]

오버라이딩이란, 조상클래스로부터 상속받은 메서드를 자손 클래스에 맞게 재정의 하는 것을 말한다.

조상 클래스로부터 상속받은 메서드를 자손 클래스에서 그대로 사용할 수 없는 경우가 많기 때문에 오버라이딩이 필요하다.

더보기

[나의 답변]

c. 더 넓은 범위여야 한다.

d. 

 

[남궁성님 답변]

c. 접근 제어자는 조상의 메서드 보다 더 넓은 범위여야 한다.

d. 조상의 메서드 보다 더 많은 수의 예외를 선언할 수 있다. -- 긴가민가 했던 부분

더보기

[나의 답변]

Tv의 부모인 Product클래스에서 (매개변수가 없는) 디폴트 생성자가 적혀있지 않다.

매개변수를 가진 생성자를 형성하면, 디폴트 생성자는 컴파일러가 자동 생성해주지 않기 때문에

Product(){ }  를 개발자가 입력해주어야 한다.

더보기

[나의 답변]

자손 클래스 생성자에서 super() 를 통해 자손 클래스의 변수와 메서드를 상속받기 때문이다.

[남궁성님 답변]

▶ 다시 생각해볼 부분 : 

- 초기화는 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블럭 -> 생성자 순으로 간다. 

- 만약 상속을 했다면, 여기에서 플러스로

  내 생성자 -> 부모 생성자 : 부모의 변수를 초기화 -> 부모 변수 값 물려받음

- 만약 내 생성자에서 변수값을 고치지 않는다면 부모 변수 값이 유지될 것이다.  

더보기

[나의 답변]

*호출 순서는 들어온 순서란 건가..? 스택에 쌓이는 순서는 child부터일텐데..

호출 순서 : Child(){} -> Parent(){} -> Parent(int x)  -> Child(int x)  

실행 결과 : 1000

 

[남궁성님 답변]

Child() -> Child(int x) -> Parent() -> Parent(int x)

실행 결과는 x = 200

 

- 해설 :

 

▶ 다시 생각할 부분 : this()로 나 자신의 다른 생성자를 호출하면 컴파일러는 super()를 자동 생성하지 않는다. 

 

더보기

[나의 답변] b  --- 틀렸다! 패키지 밖에서 상속을 받으면 접근범위가 당연히 디폴트보다 넓을 텐데 왜 생각을 못했지ㅋㅋ 기왕 틀린 김에 한 번 더 숙지하고 가야겠다

[남궁성님 해설] 답은 a다. 

더보기

[나의 답변]

(궁금증.. a 보니까 든 생각. 상수는 전역(맴버필드)에 붙이는게 낫지 않을까. 지역변수에 쓰는 경우도 있을까?)

c. 오버로딩은 되는데, 오버라이딩 불가

[남궁성님의 해설]

더보기

[나의 답변]

class MyTv2 {
	private boolean isPowerOn;
	private int channel;
	private int volume;
	final int MAX_VOLUME = 100;
	final int MIN_VOLUME = 0;
	final int MAX_CHANNEL = 100;
	final int MIN_CHANNEL = 1;
	
	public void setIsPowerOn(boolean isPowerOn){
		this.isPowerOn = isPowerOn;
	}
	
	public boolean getIsPowerOn() {
		return this.isPowerOn;
	}
	
	public void setChannel(int channel) {
		this.channel = channel;
	}
	
	public int getChannel() {
		return this.channel;
	}
	
	public void setVolume(int volume) {
		this.volume = volume;
	}
	
	public int getVolume() {
		return this.volume;
	}
	
}//end class

[남궁성님 풀이]

-- 정말 private과 getter setter만 만드는데 치중하느라 MIN과 MAX를 설정할 생각을 안했다. 함정이네 함정이야.ㅠ 그런데 현장에서도 늘 이렇게 범위를 고려해야하는 건 맞기에.. 앞으로 생각의 생각을 더 해야겠다.

 

1. java.lang패키지 

- 가장 기본이 되는 패키지이며, import문 없이도 사용이 가능하다.

- 최상위 객체인 Object클래스 외에도, String, Math, Wrapper클래스가 있다.

 

1-1. Object클래스의 주요 메서드

+equals() 객체의 주소값을 비교한다.
+hashCode() 객체의 해쉬코드를 반환한다.
*모든 객체는 자신을 구분하는 고유의 해시코드를 가진다.
*자바에서는 해싱 기법을 통해 다양한 객체를 구분하여 저장한다.
+getClass() 객체의 인스턴스를 반환한다.
+toString() "클래스이름+@+해쉬코드"문자열을 반환한다.
#clone() 객체를 얕게 복사하여 반환한다.
(객체 내 포함된 객체까지는 복사되지 않으므로, 겉의 객체만 복사되면, 안의 객체는 사실상 동일한 곳을 참조하므로 복사된 객체를 수정할 때 기존 객체의 안쪽 객체 정보까지 수정될 수 있다.)

 

1-2. String클래스

- 이부분은 별도로 정리하였다.

- 간략하게 String은 "변경 불가하다"라는 점과, 그렇기에 StringBuffer와 StringBuilder로 처리할 수 있다는 점만 기억하자..

https://why-dev.tistory.com/31?category=928637 

 

[자바의 정석_복습] String 객체에 대한 이해

심플한 개발 [자바의 정석_복습] String 객체에 대한 이해 본문 JAVA/문자열, 배열 [자바의 정석_복습] String 객체에 대한 이해 심플한 개발 2022. 3. 15. 19:08 Prev 1 ··· 5 6 7 8 9 10 Next

why-dev.tistory.com

 

1-3. Math클래스

+round() : long 소수점 첫째자리에서 반올림을 한다.
(사용시, 10^x 만큼 곱하고 나누어 원하는 만큼 반올림하면 된다.)
+ceil() 올림
+floor() 버림
.... 기타

 

1-4. Wrapper클래스

- Boolean, Character, Number가 있으면 Number안에 정수형, 실수형 변수객체들이 있다.

- 문자열을 숫자로 변환하는 법 : Integer.parseInt("문자열")

- 오토박싱과 언박싱

https://why-dev.tistory.com/45

 

[자바_문법] Wrapper 클래스 이해

Wrapper클래스  Wrapper : Boolean, Byte, Integer, Long, Float, Double Wrapper클래스의 오토-언박싱과 오토-박싱  - Auto-Boxing : [Auto-Boxing 예제_Object객체배열 안에 다양한 타입의 기본형 리터럴 입력..

why-dev.tistory.com

 

 

 

[참조]

자바의 정석, 남궁성  -- 요약한 내용입니다.

'Language > Java' 카테고리의 다른 글

[자바_문법] 쓰레드  (0) 2022.04.17
[자바의정석_예제] 객체지향프로그래밍2  (0) 2022.04.13
[자바_API] 입출력 I/O  (0) 2022.04.05
[자바_API] 네트워킹  (0) 2022.04.04
[자바의정석_복습] 예외처리  (0) 2022.03.28

1. 스트림이란? 데이터를 운반하는데 사용되는 연결통로

  [생각] BJ는 온라인방송을 할 때, 왜 "스트리밍 중"이라고 할까?

 

2. 바이트기반 스트림_InputStream/OutPutStream 추상클래스 상속

입력스트림 출력스트림 입출력 대상의 종류
FileInputStream FileOutputStream 파일
ByteArrayInputStream ByteArrayOutputStream 메모리(byte배열)
PipedInputStream PipedOutputStream 프로세스(프로세스간의 통신)
AudioInputStream AudioOutputStream 오디오장치
.... .... ....

(1) InputStream 메서드

리턴타입 메소드  
int read() 입력 스트림에서 1byte씩 읽고 byte값을 int으로 반환
int read(byte[] b) 입력 스트림에서 1byte씩 읽어 byte배열에 저장, 읽은 갯수를 반환
int read(byte[] b, int off, int len) 입력 스트림에서 off부터 시작하여, len개를 읽어 byte 배열에 저장,
읽은 갯수를 반환
void close() 시스템의 자원을 반환하고 입력 스트림을 닫는다. (파일)

▶ read() 메소드

InputStream is = new FileInputStream("C:/test.jpg");
int readByte;
//모든 InputStream 하위 객체 read() : 읽은 내용이 없으면 -1 반환
while((readByte = is.read()) != -1){}

▶ 키보드에서 읽어오기 : System.in

package mymain.input;

import java.io.InputStream;

public class _01_KeyboardInputTest {

	public static void main(String[] args) throws Exception {
		int ch;
		
		//키보드의 입력값을 받는 inputStream
		//System객체 내에 포함관계로 inputStream이 생성되어 있는 상태
		InputStream is = System.in; 
		
		System.out.println("종료하려면 [Ctrl+Z]");
		
		while((ch = is.read()) != -1) {
			System.out.printf("%c",ch);
		}
	}

▶ 파일에서 읽어오기 : FileInputStream("파일경로")

package mymain.input;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class _02_FileInputTest {
	public static void main(String[] args) throws IOException {
		InputStream is = new FileInputStream("src/mymain/input/_02_FileInputTest.java");
		
		int ch;
		
		while((ch = is.read())!=-1) {
			System.out.printf("%c",ch);
		}
		
		is.close();
	}
}

▶ 네트워크에서 읽어오기 : URL(String url) > openStream()

package mymain.input;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class _03_NetWorkInputStream {
	public static void main(String[] args) throws IOException {
		URL url = new URL("https://www.naver.com");
		InputStream is = url.openStream();
		
		int ch;
		
		while((ch = is.read())!=-1) {
			System.out.printf("%c",ch);
		}
	}
}

 

(2) OutputStream 메서드

리턴타입 메소드  
void write() 출력 스트림으로 1byte씩 보낸다.
void write(byte[] b) 출력 스트림에 byte[] b의 값을 보낸다.
void write(byte[] b, int off, int len) 출력 스트림에 off부터 시작해서 len개 만큼 보낸다.
void flush() 버퍼에 잔류하는 모든 바이트를 출력
void close() 시스템의 자원을 반납하고 출력 스트림을 닫는다. (파일)

▶ read() 메소드

OutputStream os = new FileOutputStream("C:/test.txt");
byte[] data = "ABC".getBytes();
for(int i = 0; i < data.length; i++){
	os.write(data[i]);
}

 

▶ 모니터로 출력하기 : System.out

package mymain.output;

import java.io.IOException;
import java.io.OutputStream;

public class _01_MonitorTest {
	public static void main(String[] args) throws IOException {
		OutputStream os = System.out;
		
		//자바 -> 출력 스트림 -> 키보드버퍼로 문자를 전송
		os.write(65);
		
		String msg = "안녕";
		byte[] msg_bytes = msg.getBytes();
		os.write(msg_bytes);
		
		int n = 1004;
		String s = String.valueOf(n);
		os.write(s.getBytes());
		
		boolean bOk = true;
		String b = String.valueOf(bOk);
		os.write(b.getBytes());
		
		//키보드 커퍼를 비우면서 콘솔로 전송
		os.flush();
	}
}

▶ 파일로 출력하기 : FileOutputStream("파일경로");

package mymain.output;

import java.io.FileOutputStream;
import java.io.OutputStream;

public class _02_FileOutTest {

	public static void main(String[] args) throws Exception{
		OutputStream os = new FileOutputStream("a.txt");
		
		os.write('A');
		
		String name = "홍길동";
		byte[] sArr = name.getBytes();
		os.write(sArr);
		
		int n = 1994;
		os.write(String.valueOf(n).getBytes());
		
		os.flush();
		
		os.close();
	}

}

 

(3) 바이트 배열 단위로 읽어오기/보내기

가. InputStream/OutputStream의 read(byte[] b), write(byte[] b) 사용

package mymain.input;

import java.io.FileInputStream;
import java.io.InputStream;

public class _04_InputStream_Array {
	public static void main(String[] args) throws Exception{
		InputStream is = new FileInputStream("src/mymain/input/_04_InputStream_Array.java");
		
		int readByteNo;
		byte[] readBytes = new byte[8];
        //           is.read(readBytes, 1, 8); <- index 1부터 8개
		readByteNo = is.read(readBytes);
		
		for(int i = 0; i < readBytes.length; i++) 
			System.out.printf("%c",readBytes[i]);
		
		is.close();
	}
}
package mymain.output;

import java.io.FileOutputStream;
import java.io.OutputStream;

public class _03_OutputStream_Array {
	public static void main(String[] args) throws Exception{
		OutputStream os = new FileOutputStream("a2.txt");
		
		byte[] output = "ABC".getBytes();
		
		// os.write(output,1,2); /*: index1부터 2개*/
		os.write(output);
		
		os.close();
	}
}

 

나. ByteArrayInputStream/ByteArrayOutputStream 객체 사용

package mymain.input;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;

public class _04_InputStream_Array2 {
	public static void main(String[] args) throws Exception{
		byte[] inSrc = {0,1,3,4,5,6};
		byte[] outSrc = null;
		
		ByteArrayInputStream input = null;
		ByteArrayOutputStream output = null;
		
		input = new ByteArrayInputStream(inSrc);
		output = new ByteArrayOutputStream();
		
		int data = 0;

		while((data = input.read()) != -1) {
			output.write(data);
		}
		
		outSrc = output.toByteArray();
		
		System.out.println("Input Source : "+Arrays.toString(inSrc));
		System.out.println("Output Source : "+Arrays.toString(outSrc));
	}
}

>> 결과

Input Source : [0, 1, 3, 4, 5, 6]
Output Source : [0, 1, 3, 4, 5, 6]

 

 

3. 문자기반 스트림_Reader,Writer 추상클래스 상속

입력스트림 출력스트림 입출력 대상의 종류
FileReader FileWriter 파일
ByteArrayReader ByteArrayWriter 메모리(byte배열)
PipedReader PipedWriter 프로세스(프로세스간의 통신)
StringReader StringWriter 문자열
.... .... ....

 

4. 보조스트림_Filterxxxxx, Bufferedxxxxx, Objectxxxxx

입력스트림 입출력 대상의 종류
Filterxxxxx 필터를 이용한 입출력 처리
Bufferedxxxxxx 버퍼를 이용한 입출력 향상 (버퍼에 바이트/문자 올려두고, 한 줄씩 출력 가능-nextLine())
Objectxxxxxx 객체 직렬화/역직렬화

 

 

 

[참조]

이것이 자바다 

자바의 정석, 남궁성 지음

1. 네트워킹이란? 

두 대 이상의 컴퓨터를 케이블로 연결하여 네트워크를 구성하는 것

* 자바에서는 java.net 패키지를 활용해 네트워크 어플의 데이터 통신을 쉽게 작성 가능하다.

https://www.youtube.com/watch?v=yR4hnj5XNP4&t=5s 


  [참조 : OSI 7 계층, TCP 4 layer]
  https://velog.io/@dyllis/OSI-7%EA%B3%84%EC%B8%B5-%EC%A0%95%EB%A6%AC
  - OSI 7계층 : 물리계층 - > 데이타 링크 계층/ -> 네트워크계층/ -> 전송계층 / -> 세션 계층 -> 표현 계층 -> 응용계층

 

2. 클라이언트와 서버

* 서비스란? 서버가 클라이언트로부터 요청받은 작업을 처리하여 그 결과를 제공하는 것

- 클라이언트와 서버와의 관계

클라이언트 <-> 서버
[1] 연결을 요청
[3] 처리 요청
  [2] 연결 수락
[4] 처리/응답 (서비스 제공)

- 서버의 모델

명칭 서버 기반 모델 (server-based model) P2P모델(peer-to-peer model)
내용 전용 서버를 둠 전용 서버 없이 각 클라이언트가 서버역할 동시수행
장/단점 - 안정적인 서비스 제공 가능
- 공유데이터의 관리와 보완이 용이
- 서버 구축 비용과 관리 비용이 든다.
- 서버 구축 및 운용비용을 절감 가능
- 자원의 활용을 극대화 가능
- 자원의 관리가 어려움
- 보안이 취약

 

3. IP주소 : "내 컴퓨터"를 나타내는 주소. 

https://www.youtube.com/watch?v=IAS3U5ZiI8c 

코딩하는거니님의 IP에 대한 설명

- 4byte로 0~255사이로 표현 (ex. 255.255.255.0)

- 앞의 3byte는 네트워크 주소 + 뒤 1byte는 호스트 주소

- 명령프롬프트에서 "ipconfig/All" 또는 "ipconfig"를 치면 확인 가능

 

3-1. java.net패키지의 InetAddress클래스

[1] 로컬 컴퓨터에서 IP 주소 얻으려 할 때

//객체 생성
InetAddress ip = InetAddres.getLocalHost();

//객체 이름, 주소 추출 : String으로 반환
String ipName = ip.getHostName();
String ipAddress = ip.getHostAddress();

 

[2] 도메인 이름으로 IP 주소 얻으려 할때

//도메인에서 단일 ip 주소 가져오기
InetAddress ip = InetAddress.getByName("www.naver.com");

//도메인에서 여러개의 ip주소 가져오기
InetAddress[] ipArr = InetAddress.getAllByName("www.naver.com");

 

4. URL(Uniform Resource Locator)

- 형태 : 프로토콜://호트스명:포트번호/경로명/파일명?쿼리스트링#참조 

- 예시 ) http://www.naver.com:80/sample/hello.html?refer=codechobo#index1

프로토콜 서버와 통신할 때 사용되는 통신규약(HTTP)
호스트명 자원을 제공하는 서버명(ex.www.naver.com)
포트번호 통신에서 사용되는 서버의 포트 번호
경로명 경로
파일명 파일명 (ex. index.html)
쿼리 URL에서 ? 이후의 부분 
참조 URL에서 # 이후의 부분

※ Filezilla에서 보는 호스트와 포트, 사용자명 개념

→ 호스트 : 도메인을 작성하거나, ip주소를 작성하는 공간

→ 사용자명 : 해당 호스트 사용자명 (보통 회사에서 지정해주는 게 있다.)

→ 비밀번호 : 접속 시 비밀번호

→ 포트 : 통신에서 사용되는 서버의 포트 번호 (일반적으로 FTP포트는 21이 가장 많다)

 

5. 소켓 프로그래밍

[1] 소켓에 대하여

- 소켓이란?

  프로세스 간의 통신에 사용되는 양쪽 끝단으로

  네트워크 기능(OS의 네트워크 라이브러리)을 용이하게 이용하기 위한 각 언어별 모듈(객체)이다.

- 모든 소켓은 각각 자신만의 InputStream, OutputStream을 가지고 있다.

- JVM은 각 운영체제별로 다르게 작동하며, 각 운영체제의 네트워크 라이브러리에 맞춘 소켓을 사용한다.

[2] 포트란?

- 같은 컴퓨터 내에서 프로그램을 식별하는 번호

- 0~65535 범위 (총 65536개) 값을 가질 수 있다.

- 세 가지 범위로 구분

(1) Well Known : 0~1023, ICANN가 애플리케이션용으로 미리 예약한 포트로 FTP, Telnet 등에서 사용

(2) Registed : 1024~49151, 회사에서 등록해서 사용 가능한 포트값

(3) Dynamic or Private : 49152~65535, 운영체제가 부여하는 동적 포트 또는 개인 목적의 포트

 

6. TCP와 UDP 프로토콜

- 클라이언트와 서버를 연결하는 프로토콜에는 여러가지 종류가 있다. 

- TCP,UDP 외에도 통신 프로토콜로 HTTP 등이 있다.

항목 TCP UDP
연결방식 연결기반
- 연결 후 통신(전화기)
비연결기반
- 연결 없이 통신 (소포)
특징 데이터의 경계를 구분 안함 (바이트스트림)
신뢰성 높은 데이터 전송
- 데이터의 전송순서가 보장됨
- 데이터의 수신여부를 확인함
  (데이터가 손실되면 재전송됨)
- 패킷을 관리할 필요가 없음
UDP보다 전송속도가 느림
데이터 전송용량의 제한이 없음
데이터의 경계를 구분함(datagram)
신뢰성 낮은 데이터 전송
- 데이터의 전송순서가 바뀔 수 있음
- 데이터의 수신여부를 확인안함
  (데이터가 손실되어도 알 수 없음)
- 패킷을 관리해주어야 함
TCP보다 전송 속도가 빠름
1회 전송량 512byte
관련 클래스 Socket

ServerSocket
DatagramSocket
DatagramPacket
MulticastSocket
통신 방식 Uni-cast (1:1) BroadCast(불특정 다수) 
- local broadcast
pf. xxx.xxx.xxx.255 로 일괄 전달
- global broadcast
pf. 255.255.255.255 로 일괄 전달

MultiCast(특정 다수) 
pf. 회원 가입 대상자들만 전달
pf. 224.0.0.1 ~ 239.255.255.255

[참고] 

  유니캐스트 VS 브로드캐스트 VS 멀티캐스트
  https://m.blog.naver.com/wnrjsxo/221250742423

 

7. TCP 소켓 프로그래밍

- "이것이 자바다" 영상의 아래 그림이 TCP를 이해하는데 많은 도움을 주는 것 같다. 

[이것이 자바다] 참조

[1] 송신 방법

package tcpProtocol;

import java.io.OutputStream;
import java.net.Socket;

public class BasicSend {

	public static void main(String[] args) throws Exception{
		//[1] 소켓을 연다.(연결할 서버소켓의 주소와 포트를 작성)
		Socket socket = new Socket("localhost",50000);
		OutputStream os = socket.getOutputStream();
		
		for(int i = 1; i <= 3; i++) {
			//[2] 소켓의 OutputStream을 통해 byte단위의 데이터를 전송한다.
			String data = "데이터"+i;
			os.write(data.getBytes("UTF-8"));
		}
		os.flush();
		
		//[3] 소켓 연결 끊기
		//socket.close(); --> 의도적인 종료 : -1 값을 전달한다.
		socket.close();
	}

}

 

[2] 수신 방법

package tcpProtocol;

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

public class BasicAccept {

	public static void main(String[] args) throws Exception{
		//[1] 서버 소켓을 연다.
		ServerSocket serverSocket = new ServerSocket(50000);
		
		try {
			//[2] 소켓을 연다.
			Socket socket = serverSocket.accept();
			InputStream is = socket.getInputStream();
			
			//무한 루프로 수신 대기
			System.out.println("[수신 데이터]");
			while(true) {
				//[3] InputStream을 통해 바이트단위 데이터를 가져온다.
				byte[] byteArr = new byte[300]; //한글 3byte->100자씩 읽을 것
				int len = is.read(byteArr);
				if(len == -1) break;
				String data = new String(byteArr,0,len,"UTF-8");
				//[4] 수신 data 콘솔에 출력
				System.out.println(data);
			}
		} catch (IOException e) {
			System.out.println("[연결 종료]");
		}
	
	}

}

 

[연습 예제_1] TCP 1:1 전송방식으로 로컬컴퓨터에서 에코메시지 전달하기

<Client>

package tcpProtocol;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.*;

public class Client extends JFrame{
	
	JTextArea textMonitor;
	JTextField textInput;
	JButton button;
	Socket socket;
	
	Client(){
		/* Initial Window UI Design  */
		super("Chat for Client");
		setLocation(300,300);
		setVisible(true);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		init_UiDesign();
		pack();
		
		/* TCP Socket Communication */
		init_buttonAction();
		init_socket();
		
	}//end Client()
	
	/////////////////////////////////////////////////////
	
	/* TCP Socket Communication Method */
	
	private void init_buttonAction() {
		
		button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				String textMessage = String.format("[사용자] %s%n", textInput.getText().trim());
				if(textMessage.isEmpty()) {
					JOptionPane.showMessageDialog(textMonitor,"메세지를 입력하세요.");
					return;
				}else {
					//textMonitor.append(textMessage);
					echo_message();
					textInput.setText("");
					return;
				}
			}
		});
	}
	
	private void init_socket() {
		try {
			socket = new Socket("localhost",50000);
		} catch (UnknownHostException e) {
			System.out.println("해당 호스트를 찾을 수 없습니다.");
		} catch (IOException e) {
			System.out.println("포트가 비정상적으로 닫혀있습니다.");
		}
	}

	protected void echo_message() {
		send_message();
		receive_message(); 
	}


	private void send_message() {
		//send Message to server
		try {
			OutputStream outStream = socket.getOutputStream();
			String userMessage = String.format("[사용자] %s%n", textInput.getText().trim());
				//append message to Monitor
			textMonitor.append(userMessage);
			outStream.write(userMessage.getBytes());
			outStream.flush();
		} catch (IOException e) {
			System.out.println("전송에 오류가 발생했습니다.");
		}
	}
	
	private void receive_message() {
		//receive Message from server
		try {
			byte[] readBytes = new byte[300];
			int readNum = socket.getInputStream().read(readBytes);
			String echoedMessage = new String(readBytes,0,readNum);
			
			//append message to Monitor
			textMonitor.append(echoedMessage);
		} catch (IOException e) {
			System.out.println("수신에 오류가 발생했습니다.");
		}
	}

	

	/* UI Design Method */
	
	private void init_UiDesign() {
		//textMonitor : where chat text reveals
		textMonitor = new JTextArea();
		textMonitor.setBackground(new Color(0x7BC4C4));
		textMonitor.setEditable(false);
		JScrollPane jsp = new JScrollPane(textMonitor);
		textMonitor.setPreferredSize(new Dimension(300,200));
		this.add(jsp);
		
		//textInput : where user types texts & send
		JPanel jpl = new JPanel(new BorderLayout());
		textInput = new JTextField();
		button = new JButton("전송");
		jpl.add(textInput);
		jpl.add(button,"East");
		this.add(jpl,"South");
	}

	public static void main(String[] args) {
		new Client();
	}//end main
}

 

<Server>

package tcpProtocol;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.*;

public class Server extends JFrame{
	
	JTextArea textMonitor;
	JTextField textInput;
	JButton button;
	ServerSocket serverSocket;
	Socket socket;
	
	Server(){
		/* Initial Window UI Design  */
		super("Chat for Server");
		setLocation(300,300);
		setVisible(true);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		init_UiDesign();
		pack();
		
		/* TCP Socket Communication */
		init_socket();
		
	}//end Client()
	
	
	/////////////////////////////////////////////////////
	
	/* TCP Socket Communication Method */
	
	private void init_socket() {
		try {
			serverSocket = new ServerSocket(50000);
			socket = serverSocket.accept();
			while(true) {
				//receive Message from client
				byte[] readBytes = new byte[300];
				int readNum = socket.getInputStream().read(readBytes);
				String[] userMessage = new String(readBytes,0,readNum).split("]");
				
				//append message to Monitor
				textMonitor.append(new String(readBytes,0,readNum));
				
				//send Message to client
				OutputStream outStream = socket.getOutputStream();
				String echoedMessage = String.format("[에코]%s%n",userMessage[1]);
					//append message to Monitor
				textMonitor.append(echoedMessage);
				outStream.write(echoedMessage.getBytes());
				outStream.flush();
			}
			
		} catch (IOException e) {
			JOptionPane.showMessageDialog(this, e.getMessage());
		}
		
	}

	/* UI Design Method */
	
	private void init_UiDesign() {
		//textMonitor : where chat text reveals
		textMonitor = new JTextArea();
		textMonitor.setBackground(new Color(0x7BC4C4));
		textMonitor.setEditable(false);
		JScrollPane jsp = new JScrollPane(textMonitor);
		textMonitor.setPreferredSize(new Dimension(300,200));
		this.add(jsp);
		
		//textInput : where user types texts & send
		JPanel jpl = new JPanel(new BorderLayout());
		textInput = new JTextField();
		button = new JButton("전송");
		jpl.add(textInput);
		jpl.add(button,"East");
		this.add(jpl,"South");
	}

	public static void main(String[] args) {
		new Server();
	}//end main
}

>>결과

 

 

8. UDP 소켓 프로그래밍

- UDP는 소포와 같이 서버소켓을 통한 연결 없이 수신, 송신만 가능한 형태이다.

- 통신 선로가 고정적이지 않음

- 데이터 손실이 발생 가능

- 대신 TCP보다는 빠르게 전송이 가능하다

이것이 자바다 참조

[1] 송신하는 법

//송신하는 법
//[1] DatagramSocket를 연다.
DatagramSocket datagramSocket = new DatagramSocket();
//만약, multi-cast방식으로 전달할 경우, 
//MulticastSocket multicastSocket = new MulticastSocket();
InetAddress ia = InetAddress.getByName("localhost"); //수신되는 곳의 주소

//[2] 전달할 데이터를 패킷으로 패킹한다.
String data = "전달 데이터";
byte[] byteArr = data.getBytes("UTF-8"); //UTF-8방식으로 바이트 변환
DatagramPacket packet = new DatagramPacket(
	byteArr, byteArr.length,ia,포트번호
);

//[3] DatagramSocket을 통해 패킷을 전송한다.(바이트단위로 전송된다)
datagramSocket.send(packet);

//[4] DatagramSocket을 닫아준다.
datagramSocket.close();

[2] 수신하는 법

//수신하는 법
//[1] DatagramSocket을 연다.
DatagramSocket datagramSocket = new DatagramSocket(포트번호);

//[2] 패킷을 받을 배열과 길이를 지정한다.
DatagramPacket datagramPacket = new DatagramPacket(받은 배열을 저장할 바이트 배열,배열의 길이);

//[3] 패킷을 받는다.
datagramSocket.receive(datagramPacket);

//[4] 소켓을 닫는다.
datagramSocket.close();

 

[연습 예제_간단한 데이터 송수신]

<Client>

package udpProtocol;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Client {

	public static void main(String[] args) throws Exception{
		//[1] 데이터그램 소켓으로 가야하는 곳을 지정
		DatagramSocket datagramSocket = new DatagramSocket();
		InetAddress ia = InetAddress.getByName("localhost");
		
		for(int i = 1; i <= 3; i++) {
			//[2] 데이터그램 패킷으로 데이터를 묶어둔다. 
			String data = "데이터"+i;
			byte[] byteArr = data.getBytes("UTF-8");
			DatagramPacket datagramPacket = new DatagramPacket(
				byteArr, byteArr.length,ia,8000
			);	
			
			//[3] 패킷을 소켓을 통해 전송한다.
			datagramSocket.send(datagramPacket);
			
		}//end for
		
		//[4] 소켓을 닫는다.
		datagramSocket.close();
		
	}//end main

}

<Server>

package udpProtocol;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Server {

	public static void main(String[] args) throws Exception{
		//[1] 소켓을 연다.
		DatagramSocket datagramSocket = new DatagramSocket(8000);
		
		//[2] 패킷 단위로 데이터를 받는다.
		//쓰레드를 형성해서 무한 루프로 데이터를 받는다.
		Thread thread = new Thread() {
			@Override
			public void run() {
				System.out.println("수신 시작");
				try {
					while(true) {
						DatagramPacket packet = new DatagramPacket(new byte[100],100);
						datagramSocket.receive(packet);
						String data = new String(packet.getData(),0,packet.getLength(),"UTF-8");
						System.out.println("[받은 내용 : "+packet.getSocketAddress()+"]"+data);
					}
				} catch (IOException e) {
					System.out.println("[수신 종료]");
				}
			}
		};//end thread
		
		thread.start();
		
		Thread.sleep(10000);
		datagramSocket.close();
	}//end main

}

>> 수신 결과

수신 시작
[받은 내용 : /127.0.0.1:55273]데이터1
[받은 내용 : /127.0.0.1:55273]데이터2
[받은 내용 : /127.0.0.1:55273]데이터3
[수신 종료]

 

[참조]

- 자바의 정석, 남궁성 지음

- 이것이 자바다

- 코딩하는 거니

- 티스토리 블로그 

- 그 외 : 국비지원 수업 내용 참조

>> 실행결과

차수 : 5
---snail1---
[   1   2   3   4   5]
[  16  17  18  19   6]
[  15  24  25  20   7]
[  14  23  22  21   8]
[  13  12  11  10   9]
---snail2---
[  25  24  23  22  21]
[  10   9   8   7  20]
[  11   2   1   6  19]
[  12   3   4   5  18]
[  13  14  15  16  17]
또?(y/n) : n
----END----

[Snail 객체]

package myutil;

public class Snail {
	//Right -> Down -> Left -> Up
	//이 과정을 반복하되,
	//만약 움직이려는 방향에 값이 있을 경우, 현재 자리에서 이동하지 않고,
	 //값을 넣지 않고 방향을 전환한다.
	//Right : col++
	//Down : row++
	//Left : col__
	//Up : row--
	
	//이동 정보에 대한 상수 선언
	public static final int RIGHT = 1;
	public static final int DOWN = 2;
	public static final int LEFT = 3;
	public static final int UP = 4;
	
	//현재 이동 방향 정보를 저장할 변수
	int direction;
	
	int chasu;	
	int[][] snail_array;
	
	public void setChasu(int chasu) {
		this.chasu = chasu;
		
		System.out.println("---snail1---");
		
		//달팽이 만들기
		make_snail();
		
		//출력
		display();
		
		System.out.println("---snail2---");
		
		//달팽이 만들기
		make_snail2();
		
		//출력
		display();
	}
	
	private void make_snail() {
		//달팽이 배열 생성
		snail_array = new int[chasu][chasu];
		
		int row = 0;
		int col = -1;
		int su = 1;
		
		direction = RIGHT;
		
		//[0][0]부터 채워나가기
		for(int i = 0; i < chasu*chasu; i++) {
			if(direction == RIGHT) { //오른쪽 채우기
				col++;
				if(col == chasu || snail_array[row][col]!=0) {//이동하다 막히면
					row++;
					col--;
					direction = DOWN;
				}
			}else if(direction == DOWN) { //아래쪽 채우기
				row++;
				if(row == chasu || snail_array[row][col]!=0) {
					row--;
					col--;
					direction = LEFT;
				}
			}else if(direction == LEFT) { //왼쪽 채우기
				col--;
				if(col < 0 || snail_array[row][col]!=0) {
					row--;
					col++;
					direction = UP;
				}
			}else if(direction == UP) {//위쪽 채우기
				row--;
				if(snail_array[row][col]!=0) {
					row++;
					col++;
					direction = RIGHT;
				}
			}
			
			snail_array[row][col] = su++;
		}//end for()
	}//end snail()
	
	private void make_snail2() {
		//달팽이 배열 생성
		snail_array = new int[chasu][chasu];
		
		int row = 0;
		int col = -1;
		int su = chasu*chasu;
		
		direction = RIGHT;
		
		//[0][0]부터 채워나가기
		for(int i = 0; i < chasu*chasu; i++) {
			if(direction == RIGHT) { //오른쪽 채우기
				col++;
				if(col == chasu || snail_array[row][col]!=0) {//이동하다 막히면
					row++;
					col--;
					direction = DOWN;
				}
			}else if(direction == DOWN) { //아래쪽 채우기
				row++;
				if(row == chasu || snail_array[row][col]!=0) {
					row--;
					col--;
					direction = LEFT;
				}
			}else if(direction == LEFT) { //왼쪽 채우기
				col--;
				if(col < 0 || snail_array[row][col]!=0) {
					row--;
					col++;
					direction = UP;
				}
			}else if(direction == UP) {//위쪽 채우기
				row--;
				if(snail_array[row][col]!=0) {
					row++;
					col++;
					direction = RIGHT;
				}
			}
			
			snail_array[row][col] = su--;
		}//end for()
	}

	public void display() {
		for(int i = 0; i < chasu; i++) {
			System.out.print("[");
			for(int j = 0; j < chasu; j++) {
				System.out.printf("%4d",snail_array[i][j]);
			}
			System.out.print("]");
			System.out.println();
		}//end for()
	}
}//end Snail

[Main 함수]

package mymain;

import java.util.Scanner;
import myutil.Snail;

public class _11_Question_Snail {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int chasu;
		String yn = "y";
		Snail snail = new Snail();
		
		while(true) {
			System.out.print("차수 : ");
			chasu = scanner.nextInt();
						
			//달팽이 객체 - 차수 전달(setter)
			snail.setChasu(chasu);
			//달팽이 출력
			
			//또?
			System.out.print("또?(y/n) : ");
			yn = scanner.next();
			if(!yn.equalsIgnoreCase("y")) break;
		}//end while
		
		System.out.println("----END----");
		scanner.close();
	}//end main
	
}

+ Recent posts