대학교에서 강의로 진행된 아레테고전강독(철학적탐구)를 진행하며,"철학적 탐구"의 책에 대한 리뷰입니다.


인상 깊은 구절

명제 그것은 매우 이상한 것이다!
그것에 귀속되는 엄청난 의미 때문이다. 다른 한편으로는 이러한 의미가, 그리고 언어 논리에 대한 오해가, 명제란 비상한, 실로 비길데 없이 독특한 어떤 것을 행함이 틀림없다고 생각하도록 우리를 오도한다. (철학적 탐구 p.94)

 

사유란 비길 데 없이 독특한 것임이 틀림없다. (철학적 탐구 p.95)

 

"우리는 우리의 표현 방식에서 이상이 행하는 역할을 오해하고 있다고. 즉, 우리도 역시 그것을 놀이라고 부를 것이나, 다만 우리는 이상에 의해 눈이 멀었으며, 그런 까닭에 놀이란 낱말의 실제 적용을 똑똑히 보지 못하고 있다고 말이다. (철학적 탐구 p.97)

 

철학은 우리의 언어 수단에 의해 우리의 지성에 걸린 마법에 맞서는 하나의 투쟁이다. (철학적 탐구 p.101)

 

우리의 몰이해의 한 가지 주요 원천은,  우리가 우리의 낱말들의 쓰임을 일목요연하게 보지 못한다는 것이다. 
우리의 문법에는 일목요연성이 결여되어 있다.  일목요연한 묘사가 이해를 성사시키며, 이해란 다름 아니라 우리가 ‘연관
들을 본다’는 데 있다.  그런 까닭에 중간 고리들의 발견과 발명이 중요한 것이다. (철학적 탐구 p. 104)

 


그러나 그렇다면 그것은 놀이가 아니다?-"그렇다, 아마 당신은 그걸 놀이라고 부를 것이지만, 그럼에도 불구하고 그건 어쨋든 완벽한 놀이다 아니다" (철학적 탐구 p.97)

질문 : 규칙들에 모호함이 존재한다면, 그건 좌우간 놀이가 아니다”라고 한다. 과연 모호하다고 해서 놀이가 아닐까?

 

우리가 흔히 아는 농구라는 놀이는 1점,3점의 점수를 매기는 것은 바닥에 정확하게 선으로 확인을 한다. 하지만 규칙이 생기지 않았을 때에 당시에는 모호한 규칙인 놀이라 생각한다. 이러한 모호한 규칙들이 놀이를 진행하며 진화해 나가는 과정이라고 생각한다. 우리가 알고 있는 놀이(축구,야구,농구,원카드 게임 등등)이 아닌 새로운 놀이가 생겨났을 때도 모호한 규칙이 많이 생길거라고 생각한다. 이러한 모호한 규칙들이 해결되며 정확한 "규칙" 이 생기는 것이라고 생각한다.

 

철학에서 "논제"들을 수립하고자 한다면, 그것들에 관해서는 결코 토론이 이루어질 수 없을 것이다.
왜냐하면 그것들에 대해서는 모두가 동의할 것이기 때문이다. (철학적탐구 p. 106)

질문 : 현시점에서도 논제들을 수립하고자 하면 토론이 이루어지지 않는가?

 

개개인의 사실이나 명제에서 일반적 결론을 이끌어내는 추론법인 귀납법과 보편명제에서 특수 명제를 이끌어내는 추론법인 연역법 등으로 논제가 수립된다고 생각하여 토론이 이루어진다고 생각한다.

 

대학교에서 강의로 진행된 아레테고전강독(철학적탐구)를 진행하며,"철학적 탐구"의 책에 대한 리뷰입니다.

 


인상 깊은 구절

 

우리가 이 요소들을 설명(즉 기술)할 수는 없고 단지 명명할 수만 있다는 것은 무슨 뜻인가 
그것이 낱말이냐 문장이냐 하는 것은 그것이 발화되거나 필기되는 상황에 달려 있다. (철학적탐구 p.61)

 

우리들이 요소에 존재를 부여할 수 없는 것은, 만일 그것이 존재하지 않는다면 우리들은 그것을 명명조차 할 수 없을 터이고, 따라서 그것에 관해 전혀 아무것도 진술할 수 없을 것이기 때문이라고. (철학적탐구 p.62)

 

언어의 이름들이 지칭하는 것은 파괴 불가능해야 한다. 왜냐하면 파괴 가능한 모든 것이 파괴되어 있는 상태가 기술될 수 있어야 하기 때문이다. 그리고 이러한 기술 속에는 낱말들이 존재할 것이다. 그리고 그렇다면 그 낱말들에 대응하는 것은 파괴되어서는 안 된다. 왜냐하면 그렇지 않다면 그 낱말들은 아무 의미도 지니지 않을 것이기 때문이다. (철학적탐구 p.66)

 

규칙은 이정표처럼 있다. 이정표는 내가 가야 할 길에 관해 아무런 의심도 열어 두지 않는가? 내가 그 옆으로 지날 때 그것은 내가 어느 방향으로 가야 할지, 즉 도로를 따라서 가야 할지, 또는 들길을 따라가야 할지, 또는 들판을 가로질러 가야 할지를 보여 주는가? 그러나 내가 그것을 어느 뜻으로 따라야 하는지, 즉 손가략 방향인지, 또는(예컨대) 그 반대 방향으로인지 하는 것은 어디에 적혀 있는가? (철학적탐구 p.87~88)

 

이름들은 현실의 요소인 것만을 지칭한다. 파괴될 수 없는 것, 모든 변화 속에서 똑같이 남아 있는 것을. (철학적탐구 p. 69)

 

비트겐슈타인은 이름이 단순한 것을 지칭해야 한다는 이야기를 하고, 그 후에 단순한 것은 무엇이냐? 그리고 이와 대비되는 복학접인 것은 무엇인지에 대해 설명합니다. 이후에 <테아이테토스>의 묘사에 적용된 어떤 언어놀이를 보고 이야기하자면, 무엇이 단순한가, 복합적인가는 우리가 무엇을 단순,복잡한 것이라고 말하냐에 달려 있다고 생각합니다. 요소의 존재와 일람표에 대해 이야기 하며, 요소의 존재는 그것이 존재한다면 존재하지 않는다는 말의 가능성을 야기한다고 생각합니다. "언어의 이름들이 지칭하는 것은 파괴 불가능해야 한다. 왜냐하면 파괴 가능한 모든 것이 파괴되어 있는 상태가 기술될 수 있어야 하기 때문이다." 는 그이 이름에 대응하는 것이며, 그는 파괴될 수 있습니다. 그리고 그의 이름은 그 소지자가 파괴될 때 의미를 잃지 않습니다. "이름들은 현실의 요소인 것만을 지칭한다. 파괴될 수 없는 것, 모든 변화속에서 똑같이 남아 있는 것을." 구성 요소는 변하지 않고 남아 있는데 반해서 자신은 변하는 하나의 전체를 보기도 한다. "가족 유사성"이란 단어는 혈연관계에 있는 사람들은 서로 닮았다. 그러나 그렇다고 가족의 모든 구성원이 하나 또는 그 이상의 공통성질을 공유하는 것같이 게임들이 모두 공유하는 하나의 공통적인 본질은 없다. 라고 생각합니다.

 

대학교에서 강의로 진행된 아레테고전강독(철학적탐구)를 진행하며,"철학적 탐구"의 책에 대한 리뷰입니다.

 

"철학적 탐구"는 비트겐슈타인의 책이며, "논리-철학 논고"의 책에서 언어로 말할 수 있는 것, 말할 수 없는 것과 언어의 궁극적 본질에 대해 다루었고, "철학적 탐구"는 기존의 언어관을 수정되고, 언어의 일상적 사용과 실천에 의해서 언어를 파악할 수 있다는 주장이 제기하고, 언어놀이라는 개념의 제안을 통해 컨텍스트 안에서 언어의 의미를 파악할 수 있음을 제시합니다.


 

인상 깊은 구절

언어의 모든 낱말은 각각 어떤 것을 지칭한다"라고 우리가 말할 때, 우리가 어떤 구별을 하기를 원하는지가 정확히 설명되지 않는다면, 그로써 당장은 아직 전혀 아무것도 말해진 것이 없다. (철학적탐구 p.32)

 

우리들은 언어를 배운다는 것은 대상들을 명명하는 데 있다고 생각한다. 더 정확히 말하자면, 사람, 형태, 색깔, 고통, 기분, 수 등등을 명명하는데 있다고 생각한다. 이미 말했다시피, 명명이란 사물에 이름표를 붙이는 것과 비슷한 어떤 것이다. (철학적 탐구 p.42)

 

"우리가 사람 이름으로 그 사람을 부른다는 것이 얼마나 별난 것인지를 생각하라!" (철학적탐구 p.43)

근거) 우리는 "이것은 뭐라고 하지요?" 라고 묻도록 교육, 훈련 받았으며, 그러면 이에 대해 이름을 대는 일이 뒤이어 일어난다는 것을 뜻한다. 그리고 어떤것에 대해 이름을 대는 일이 뒤이어 일어난다는 것을 뜻한다. 그러니까, "이것은 .....(이)라고 한다"라고 말하고는 그 새로운 이름을 사용하는 언어놀이 말이다.

 

낯선 나라에 가는 사람은 때로는 그 토착민들의 언어를 그들이 그에게 해 주는 지시적 설명들을 통해 배울 것이다. 그리고 그는 이러한 설명들의 해석을 종종 추측해야하며, 때로는 옳게, 때로는 잘못 추측할 것이다 (철학적탐구 p.47)

 

낱맡이 명백히 이름이 아닌 곳에서 왜 우리들은 바로 이 낱말을 이름으로 만들려고 하는 생각에 이르는가?
우리들은 "이름"이라고 통상적으로 불리는 것에 대해서 어떤 제기하고 싶은 유혹을 받기 때문이다. 그리고 이 이의는 이렇게 표현될 수 있다. 즉, 이름은 본래 단순한 것을 지칭해야 한다고 말이다. (철학적탐구 p.53)

#1 ~ 44 까지 읽고 느낀 점

책을 한장씩 넘겨가며 읽을 때 내용에 대한 이해가 되지 않은 상태로 계속 읽어 나가면 어느 시점에서 이해되지 않는 내용들이 어느정도 정리가 되면서 이해가 되기 시작하였습니다. 하지만 전부의 내용을 이해하는 것이 아니라, 부분의 내용이 이해 되는 것이며, 이 책은 읽으면서 이해를 하는 것이 아닌 독자들의 두뇌를 계속 자극하여 스스로 사고, 생각 할 수있도록 만들어진 책이라고 생각합니다.

저자는 철학적 물음들에 직접 대답하기보다는 오히려 다양한 예시나 이야기를 통해 답을 암시하고, 단서는 주어지지만 함축적 의미는 불분명하다고 생각합니다. 

 

학교에서 공동탐구를 진행하는데 공동탐구를 참여하면서 책에 대한 다른 사람들의 생각을 들으며 소통하여 나의 생각을 정리 할려고 합니다.

Ubuntu Linux에서 Strongswan 으로 IPsec 실습하였고, GRE Tunnel 을 이용하여 터널 생성 후 진행 하였습니다.

 

GRE Tunnel 바로가기

 

 VirtualBox로 실행된 리눅스 가상머신 두개로 진행하였고, IP는 따로 공개하지 않고 설명하겠습니다.

 

host A GRE IP 10.0.0.1host B GRE IP 10.0.0.2


설정 단계

sudo vim /etc/sysctl.conf

sysctl.conf 파일에 접근합니다.

net.ipv4.ip_forward=1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects

해당 행들을 찾아 주석 처리하여 패킷 전달을 활성화 시킵니다.

sudo sysctl -p

명령어를 실행시켜 활성화 시킨 설정을 로드합니다.

 

 

/etc/ufw/before.rules

UFW 방화벽에 접근하여 다음 규칙을 추가합니다.

 

host A

*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s host B IP  -d host A IP -j MASQUERADE
COMMIT

host B IP, host A IP에 연결할 IP의 서브넷을 입력합니다.(GRE IP x) 

서브넷은 ip route show로 확인 가능합니다.

 

host B

*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s host A IP  -d host B IP -j MASQUERADE
COMMIT

host B IP, host A IP에 연결할 IP의 서브넷을 입력합니다.(GRE IP x)

서브넷은 ip route show로 확인 가능합니다.

sudo ufw disable
sudo ufw enable

방화벽 규칙이 추가되었으므로, 명령어를 입력하여 UFW를 다시 시작하여 새 규칙을 적용 시킵니다.


Ubuntu에 StrongSwan 설치

sudo apt update
sudo apt install strongswan

패키지를 업데이트하고, apt 패키지 관리자를 사용하여 strongswan 패키지를 설치합니다.

sudo systemctl status strongswan-starter

해당 명령어를 사용하여, strongswan 상태 및 활성화 여부를 확인할 수 있습니다.


StrongSwan ipsec 설정

sudo cp /etc/ipsec.conf /etc/ipsec.conf.copy
sudo nano /etc/ipsec.conf

cp 명령어를 사용하여 ipsec.conf의 파일을 복사해두고, 파일 수정을 할 수 있는 nano 명령어로 ipsec.conf 에 접근합니다.

 

host A ipsec.conf 설정

config setup
        charondebug="all"
        uniqueids=yes
conn hostA-to-hostB
        type=tunnel
        auto=start
        keyexchange=ikev2
        authby=secret
        left=10.0.0.1
        leftsubnet= host A IP
        right=10.0.0.2
        rightsubnet= host B IP
        ike=aes256-sha1-modp1024!
        esp=aes256-sha1!
        aggressive=no
        keyingtries=%forever
        ikelifetime=28800s
        lifetime=3600s
        dpddelay=30s
        dpdtimeout=120s
        dpdaction=restart

host A IP, host B IP는 연결할 IP의 서브넷 변경하고, 위 구성을 복사하여 접근한 ipsec.conf 에  붙여 넣으면 됩니다.

 

host B ipsec.conf 설정

config setup
        charondebug="all"
        uniqueids=yes
conn hostB-to-hostA
        type=tunnel
        auto=start
        keyexchange=ikev2
        authby=secret
        left=10.0.0.2
        leftsubnet= host B IP
        right=10.0.0.1
        rightsubnet= host A IP
        ike=aes256-sha1-modp1024!
        esp=aes256-sha1!
        aggressive=no
        keyingtries=%forever
        ikelifetime=28800s
        lifetime=3600s
        dpddelay=30s
        dpdtimeout=120s
        dpdaction=restart

host A IP, host B IP는 연결할 IP의 서브넷 변경하고, 위 구성을 복사하여 접근한 ipsec.conf 에  붙여 넣으면 됩니다.

sudo nano /etc/ipsec.secrets

host A, host B 연결 간 사용할 PSK를 설정하기 위해 ipsec.secrets 로 접근합니다.

 

host A

10.0.0.1 10.0.0.2 : PKS "12345"

위 행을 복사하여 붙여 넣으면 됩니다.

 

host B

10.0.0.2 10.0.0.1 : PKS "12345"

위 행을 복사하여 붙여 넣으면 됩니다.

sudo ipsec restart
sudo ipsec status

IPSec 프로그램을 다시 시작하고 연결상태를 확인합니다.

 

host A

host B

연결이 잘된 것을 확인할 수 있습니다. 

 

sudo ipsec stop
sudo ipsec start

또한 위 명령어로 IPSec을 중지하고 시작할 수 있습니다.


위에와 똑같이 환경설정을 하고, 연결을 하였는데 한쪽만 연결된 상황입니다. 이러한 이유를 확인 해보기 위해 많은 시도를 했는데 확인하지 못했습니다. 

 

host A

host B

결과는 host A는 연결이 잘 되었지만 host B는 연결 대기 상태이다. 이러한 문제를 Wireshark 분석 툴로 확인해 보았습니다.

host A(10.0.0.1) 에서 ipsec을 실행 시키면 자신의 SPI를 생성하여 host B(10.0.0.2)로 연결 요청을 보냅니다. 그 후 host B에서 host A의 연결 요청을 받고 자신의 SPI를 생성하여 host A에게 응답을 보내며 연결이 되는 걸로 이해 하고 있습니다.

하지만, 필자는 host B에서 ipsec을 실행시키면 host A의 연결 요청을 받아 응답하는게 아닌, host B에서 다른 자신의 SPI을 생성하여 host A로 보내고 이것으로 연결이 됩니다. 그래서 host B는 연결이 되지만, host A는 연결대기상태가 됩니다.

host A(10.0.0.1) 에서 ipsec을 실행 시키면 host B(10.0.0.2)로 연결 요청을 보냅니다.

host B에서 ipsec을 실행 시키면 응답 요청이 아닌 새로운 SPI 생성 후 host A에게 연결 요청을 보냅니다.

host A는 host B에게 받은 연결요청을 응답하여 host B에게 응답한 SPI를 생성하여 보냅니다.

host B는 host A와 연결이 되지만, host A는 연결대기상태가 됩니다.

 

 

'Network > GRE Tunnel' 카테고리의 다른 글

GRE Tunnel  (0) 2022.07.29

'혼자 공부하는 머신러닝 + 딥러닝' 교재를 공부한 내용입니다.

 

해당 교재는 코랩으로 진행하지만, 필자는 파이참으로 진행하였습니다.


# 도미 데이터 준비하기
bream_length = [25.4, 26.3, 26.5, 29.0, 29.0, 29.7, 29.7, 30.0, 30.0, 30.7, 31.0, 31.0,
                31.5, 32.0, 32.0, 32.0, 33.0, 33.0, 33.5, 33.5, 34.0, 34.0, 34.5, 35.0, 
                35.0, 35.0, 35.0, 36.0, 36.0, 37.0, 38.5, 38.5, 39.5, 41.0, 41.0]
bream_weight = [242.0, 290.0, 340.0, 363.0, 430.0, 450.0, 500.0, 390.0, 450.0, 500.0, 475.0, 500.0, 
                500.0, 340.0, 600.0, 600.0, 700.0, 700.0, 610.0, 650.0, 575.0, 685.0, 620.0, 680.0, 
                700.0, 725.0, 720.0, 714.0, 850.0, 1000.0, 920.0, 955.0, 925.0, 975.0, 950.0]

도미의 길이와, 무게 각 리스트에 넣었습니다.

 

import matplotlib.pyplot as plt # matplotlib의 pylot 함수를 plt 로 줄여서 사용

plt.scatter(bream_length, bream_weight)
plt.xlabel('length')            # x축은 길이
plt.ylabel('weight')            # y축은 무게
plt.show()

산점도 그래프를 그릴 수 있는 패키지인 맷플롭립을 import한 후 산점도를 그리는 함수인 scatter을 사용하여 xlabel, ylabel 함수를 이용해 x축은 length, y축은 weight 이름을 표시하였고, show 함수를 이용해 그래프를 확인해봅니다.

 

도미는 길이가 길수록 무게가 많이 나가는 것을 확인 할 수 있습니다. 또한 산점도 그래프가 일직선에 가까운 형태로 나타는 경우를 선형적이라 말합니다.

# 빙어 데이터 준비하기
smelt_length = [9.8, 10.5, 10.6, 11.0, 11.2, 11.3, 11.8, 11.8, 12.0, 12.2, 12.4, 13.0, 14.3, 15.0]
smelt_weight = [6.7, 7.5, 7.0, 9.7, 9.8, 8.7, 10.0, 9.9, 9.8, 12.2, 13.4, 12.2, 19.7, 19.9]

 

또한 빙어 데이터도 도미와 동일하게 넣습니다.

plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

 

도미와 빙어를 같이 산점도 그래프로 확인해봅니다.

주황색 점은 빙어의 산점도, 파란색 점은 도미의 산점도입니다.

빙어는 길이가 늘어나도 무게가 많이 늘지 않는 것을 확인 할 수 있습니다.

 

length = bream_length + smelt_length
weight = bream_weight + smelt_weight

fish_data = [[l,w] for l,w in zip(length, weight)] # 리스트 내포를 이용한 fish_data 2차원 리스트 제작. 사이킷런을 사용하기 위해선 2차원 리스트로 구현해야 됨.

k-최근접 이웃 알고리즘을 사용하기 전에 도미와 빙어의 데이터를 하나의 데이터로 합쳤고, 머신러닝 패키지인 사이킷런을 사용하기 위해선 2차원 리스트를 만들어야 하기 때문에 zip 함수와, 리스트 내포 구문을 활용하여 2차원 리스트를 만듭니다.

 

출력 결과는 다음과 같습니다.

print(fish_data)

[[25.4, 242.0], [26.3, 290.0], [26.5, 340.0], [29.0, 363.0], [29.0, 430.0], [29.7, 450.0], [29.7, 500.0], [30.0, 390.0], 
[30.0, 450.0], [30.7, 500.0], [31.0, 475.0], [31.0, 500.0], [31.5, 500.0], [32.0, 340.0], [32.0, 600.0], [32.0, 600.0], 
[33.0, 700.0], [33.0, 700.0], [33.5, 610.0], [33.5, 650.0], [34.0, 575.0], [34.0, 685.0], [34.5, 620.0], [35.0, 680.0], 
[35.0, 700.0], [35.0, 725.0], [35.0, 720.0], [36.0, 714.0], [36.0, 850.0], [37.0, 1000.0], [38.5, 920.0], [38.5, 955.0], 
[39.5, 925.0], [41.0, 975.0], [41.0, 950.0], [9.8, 6.7], 
[10.5, 7.5], [10.6, 7.0], [11.0, 9.7], [11.2, 9.8], [11.3, 8.7], [11.8, 10.0], [11.8, 9.9], [12.0, 9.8], 
[12.2, 12.2], [12.4, 13.4], [13.0, 12.2], [14.3, 19.7], [15.0, 19.9]]

 

머신 러닝은 정답과 같이 알려주어야 하므로 도미 1, 빙어 0 정답 리스트를 만듭니다.

fish_target = [1] * 35 + [0] * 14 # 도미와 빙어를 구분해주는 target. 1일 경우 도미, 0일 경우 빙어를 나타냄.

 

from sklearn.neighbors import KNeighborsClassifier # 사이킷런 패키지에서 k-최근접 이웃 알고리즘을 구현한 클래스

kn = KNeighborsClassifier()

kn.fit(fish_data, fish_target) # fit() 메소드는 학습시키는 역할을 한다.

사이킷런 패키지에서 k-최근접 이웃 알고리즘을 구현한 클래스를 사용하기위해 KNeighborsClassifier를 import하고,

객체를 생성한 후 머신러닝을 훈련하는 fit 메소드를 이용하여 생선 데이터, 정답을 주어 훈련 시킵니다.

 

print(kn.score(fish_data, fish_target)) # 훈련이 얼마나 잘 됐는지를 평가하는 score() 메소드. 0부터 1까지 출력된다. 1이면 완벽하게 학습된것이고, 0.5면 절반.fish_target = [1] * 35 + [0] * 14 # 도미와 빙어를 구분해주는 target. 1일 경우 도미, 0일 경우 빙어를 나타냄.

1.0

훈련이 잘되었는지 평가하는 메소드인 score 로 확인해보면 정확도가 100%인 것을 확인할 수 있습니다.

 

plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.scatter(30,600, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

새로운 생선 데이터를 생성하여 삼각형으로 산점도 그래프를 그려 확인해봅니다.

 

새로운 데이터는 파란색 점인 도미 데이터에 가까운 것을 확인 할 수있습니다. 이러한 새로운 데이터를 우리가 훈련 시킨 머신러닝 모델에 입력하여 확인 해보겠습니다.

print(kn.predict([[30,600]]))     # predict() 메소드는 새로운 데이터의 정답을 예측한다.

[1]

# k-최근접 이웃 알고리즘은, 어떤 데이터에 대한 답을 구할 때 주위의 다른 데이터를 보고 다수를 차지하는 것을 정답으로 한다.
# 위 [30,600]의 데이터는 주위에 도미 데이터가 많으므로 이 데이터를 도미라고 판단하고 1을 출력함

새로운 데이터의 정답을 예측할 수 있는 predict 메소드로 입력하여 확인해보면 반환된 값이 1이라는 것을 알 수 있고, 우리가 훈련 시킨 머신러닝 모델(k-최근접 이웃 알고리즘)도 새로운 데이터가 도미라는 것을 확인할 수 있습니다.

 

# 보통 k-최근접 이웃 알고리즘은 주변에서 가장 가까운 5개의 데이터를 가지고 비교를 진행, 하지만 이 코드에선 5개로 비교하는 수를 49개. 모든 개수를 이용하여 비교한다는 의미이다.
kn49 = KNeighborsClassifier(n_neighbors=49)

k-최근접 이웃 알고리즘은 가장 가까운 5개의 데이터를 가지고 비교를 진행하지만, 49개의 데이터로 확인하는 모델을 다시 만들었습니다.

 

kn49.fit(fish_data, fish_target)
print(kn49.score(fish_data, fish_target))  # fish_data 의 데이터 49개 중 도미가 35개 로 다수를 차지하므로, 어떤 데이터를 넣어도 무조건 도미로 예측할 것이다.
0.7142857142857143
print(35/49)                        # 출력되는 수가 49개로 설정해놓고 데이터를 예측 할 수 있는 정확도이다.
0.7142857142857143

새로운 모델을 학습 시키고 정확도를 확인해 보면, 49개중 35개만 맞춘 정확도를 확인 할 수 있고, 도미만 맞추었다는 것을알 수 있습니다. 만약 모델을 학습시키는 데이터의 양이 많다면, kn49의 모델이 더욱 더 정확할 수 있지만, 해당 모델의 학습시키는 양은 작아 kn 모델이 더 정확한 것을 확인할 수 있습니다.

 


전체소스코드

# 도미 데이터 준비하기
bream_length = [25.4, 26.3, 26.5, 29.0, 29.0, 29.7, 29.7, 30.0, 30.0, 30.7, 31.0, 31.0,
                31.5, 32.0, 32.0, 32.0, 33.0, 33.0, 33.5, 33.5, 34.0, 34.0, 34.5, 35.0, 
                35.0, 35.0, 35.0, 36.0, 36.0, 37.0, 38.5, 38.5, 39.5, 41.0, 41.0]
bream_weight = [242.0, 290.0, 340.0, 363.0, 430.0, 450.0, 500.0, 390.0, 450.0, 500.0, 475.0, 500.0, 
                500.0, 340.0, 600.0, 600.0, 700.0, 700.0, 610.0, 650.0, 575.0, 685.0, 620.0, 680.0, 
                700.0, 725.0, 720.0, 714.0, 850.0, 1000.0, 920.0, 955.0, 925.0, 975.0, 950.0]

import matplotlib.pyplot as plt # matplotlib의 pylot 함수를 plt 로 줄여서 사용

plt.scatter(bream_length, bream_weight)
plt.xlabel('length')            # x축은 길이
plt.ylabel('weight')            # y축은 무게
plt.show()

# 빙어 데이터 준비하기
smelt_length = [9.8, 10.5, 10.6, 11.0, 11.2, 11.3, 11.8, 11.8, 12.0, 12.2, 12.4, 13.0, 14.3, 15.0]
smelt_weight = [6.7, 7.5, 7.0, 9.7, 9.8, 8.7, 10.0, 9.9, 9.8, 12.2, 13.4, 12.2, 19.7, 19.9]

plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

# 첫 번째 머신러닝 프로그램

length = bream_length + smelt_length
weight = bream_weight + smelt_weight

fish_data = [[l,w] for l,w in zip(length, weight)] # 리스트 내포를 이용한 fish_data 2차원 리스트 제작. 사이킷런을 사용하기 위해선 2차원 리스트로 구현해야 됨.

print(fish_data)

fish_target = [1] * 35 + [0] * 14 # 도미와 빙어를 구분해주는 target. 1일 경우 도미, 0일 경우 빙어를 나타냄.

from sklearn.neighbors import KNeighborsClassifier # 사이킷런 패키지에서 k-최근접 이웃 알고리즘을 구현한 클래스

kn = KNeighborsClassifier()

kn.fit(fish_data, fish_target) # fit() 메소드는 학습시키는 역할을 한다.

print(kn.score(fish_data, fish_target)) # 훈련이 얼마나 잘 됐는지를 평가하는 score() 메소드. 0부터 1까지 출력된다. 1이면 완벽하게 학습된것이고, 0.5면 절반.

# k-최근접 이웃 알고리즘

plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.scatter(30,600, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

print(kn.predict([[30,600]]))     # predict() 메소드는 새로운 데이터의 정답을 예측한다.
# k-최근접 이웃 알고리즘은, 어떤 데이터에 대한 답을 구할 때 주위의 다른 데이터를 보고 다수를 차지하는 것을 정답으로 한다.
# 위 [30,600]의 데이터는 주위에 도미 데이터가 많으므로 이 데이터를 도미라고 판단하고 1을 출력함

print(kn._fit_X)
print(kn._y)

# 보통 k-최근접 이웃 알고리즘은 주변에서 가장 가까운 5개의 데이터를 가지고 비교를 진행, 하지만 이 코드에선 5개로 비교하는 수를 49개. 모든 개수를 이용하여 비교한다는 의미이다.
kn49 = KNeighborsClassifier(n_neighbors=49)


kn49.fit(fish_data, fish_target)
print(kn49.score(fish_data, fish_target))  # fish_data 의 데이터 49개 중 도미가 35개 로 다수를 차지하므로, 어떤 데이터를 넣어도 무조건 도미로 예측할 것이다.
print(35/49)                        # 출력되는 수가 49개로 설정해놓고 데이터를 예측 할 수 있는 정확도이다.

GRE Tunnel (Generic Routing Enapsulartion)

GRE는 라우팅이 불가능한 패킷을 라우팅 가능한 패킷의 내부에 넣어서 전송할 때 사용하는 터널링 프로토콜이다. 

GRE Tunnel을 실습해 보았습니다.

 

Tunnel은 기존의 IP헤더에 새로운 헤더를 붙여서 사용하게 됩니다.(캡슐화)

IP 헤더 Protocol GRE 헤더
Source IP Destination IP IP GRE Source IP GRE Destination IP
host A IP host B IP   10.0.0.1 10.0.0.2

host A는 VirtualBox로 실행된 리눅스 가상머신 이고, host B는 라즈베리 파이로 진행하였고, IP와 MAC주소는 따로 공개하지 않고 설명을 진행 하겠습니다.

 

sudo modprobe ip_gre
lsmod | grep gre

 

sudo moprobe ip_gre 명령어는 GRE를 사용하기 위해 ip_gre 모듈을 로드하고, 로드가 잘 되었는지

lomod | grep gre 명령어로 확인합니다. 이 명령어는 처음 연결을 진행하는 컴퓨터에서만 진행하면 됩니다.(host A)

host A 설정

sudo ip tunnel add gre3 mode gre remote Host B IP local Host A IP ttl 255

sudo ip link set gre3 up

sudo ip addr add 10.0.0.1/24 dev gre3

host A의 리눅스 터미널

sudo ip tunnel add gre3 mode gre remote Host B IP loacl Host A IP ttl 255

연결할 주소인 Host B IP, 출발 주소 인 Host A IP 를 입력하고, ttl 255로 설정합니다. 

 

sudo ip link set gre3 up 명령어로 gre3 interface를 활성화 시킨 후, sudo ip addr add 10.0.0.1/24 dev gre3 입력하여 gre3 interface에 10.0.0.1 ip를 할당합니다.(터널 외부 IP 할당)

 

ip route show 명령어로 route를 확인해보면 빨간색 박스와 같이 할당된 것을 확인 할 수 있습니다.

host B 설정

host B 또한 host A와 같이 명령어를 입력하여 세팅합니다.

 

sudo ip tunnel add gre3 mode gre remote Host A IP local Host B IP ttl 255

sudo ip link set gre3 up

sudo ip addr add 10.0.0.2/24 dev gre3

 

ping test

host A(10.0.0.1)에서 host B(10.0.0.2)로 핑테스트를 해보면 연결이 잘 된 것을 확인 할 수 있습니다.

조금 더 자세하게 확인하기 위하여 Wireshark 분석 툴을 가지고 확인 해보았습니다.

 

host A -> host B

host A에서 host B로 ping test를 하는 Protocol인 ICMP이며, host A,B 의 MAC주소를 확인 할 수 있습니다.

 

host A -> host B

host A,B 의 IP주소와 Protocol이 Generic Routing Enapsulation인 것을 확인 할 수 있습니다.

 

host A -> host B

추가로 Tunnel을 사용하는 의미를 가지는 IP Protocol 이 있는 것을 확인 할 수 있습니다.

 

host A -> host B

host A,B 의 GRE Tunnel ip주소를 확인 할 수 있습니다.

 

host B -> host A

host B에서 host A 의 ICMP를 응답한 결과도 분석해보면 위에서 설명한듯이 host A, B의 MAC주소, IP주소 Generic Routing Encapsulation, 터널 IP 주소를 확인 할 수 있었습니다.



GRE Tunnel을 실습, 분석해보았고, 터널링을 이용하면 더 나아가 VPN 환경을 구축할 수 있습니다.


참고 바로가기

'Network > GRE Tunnel' 카테고리의 다른 글

GRE Tunnel + IPSec  (0) 2022.07.30

대망의 하이라이트 소켓 통신 부분입니다.


client

package Socket_pkg;

import java.awt.*;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import java.awt.event.*;

import Login_pkg.*;
import Puzzle_pkg.*;
import Ranking_pkg.*;

class PuzzleBoard extends Container {

	private boolean running = false; // 게임이 진행 중인가를 나타내는 변수

	private PrintWriter writer; // 상대편에게 메시지를 전달하기 위한 스트림
	private JButton changebtn; // 빈칸과 바꿀 칸 변경
	private JButton[][] numbtn = new JButton[4][4]; // 15 까지의 버튼
	private int[][] numcount = new int[4][4]; // 15까지의 숫자
	private int row = 0, col = 0;
	private int getrownum = 0, getcolnum = 0;
	protected static String timerBuffer; // 경과 시간 문자열이 저장될 버퍼 정의

	public PuzzleBoard() {
		
		// 배치
		setSize(480, 480);
		setLayout(new GridLayout(4, 4));

		int k = 1;
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++) {
				numbtn[i][j] = new JButton(String.valueOf(k));
				numbtn[i][j].setFont(new Font("굴림체", Font.BOLD, 30));
				add(numbtn[i][j]);
				numbtn[i][j].addKeyListener(new MyKeyListener());
				k++;
			}
		}

		setVisible(false);
		getNum();
		display();
	}

	// 0~16 난수발생
	public void getNum() {
		int[] num = new int[16];
		int n = 0;
		boolean Check = false;
		for (int i = 0; i < 16; i++) {
			Check = true;
			while (Check) {
				n = (int) (Math.random() * 16);
				Check = false;
				for (int j = 0; j < i; j++) {
					if (n == num[j]) // 같은 수 저장 방지
					{
						Check = true;
						break;
					}
				}
			}
			num[i] = n;
			numcount[i / 4][i % 4] = n;
			if (n == 15) { // 랜덤 칸 생성
				row = i / 4;
				col = i % 4;
			}

		}
	}

	// 디스플레이
	public void display() {

		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++) {
				if (i == row && j == col) {
					numbtn[i][j].setText(String.valueOf(""));

					numbtn[i][j].setEnabled(false);
				} else {
					System.out.println("numcount[" + i + "]" + "[" + j + "] " + numcount[i][j] + " ");
					numbtn[i][j].setText(String.valueOf(numcount[i][j] + 1));
					numbtn[i][j].setEnabled(true);
				}
			}
		}
	}

	// 종료 여부 확인 numbtn 과 k 가 같으면 종료
	public boolean isEnd() {

		int k = 1;
		try {
			for (int i = 0; i < 4; i++) {
				for (int j = 0; j < 4; j++) {
					if (Integer.parseInt(numbtn[i][j].getText()) != k)
						return false;
					System.out.println("k :" + k);
					k++;
				}
			}
		} catch (NumberFormatException e) {

		}

		if (k == 15)
			return true;

		return false;

	}

	private class MyKeyListener extends KeyAdapter {

		public void keyPressed(KeyEvent e) {

			boolean isEnd = false;
			char keyCode = e.getKeyChar();
			switch (keyCode) {
			case 'w':
				if (row == 0) {
					break;
				} else {
					changebtn = numbtn[row - 1][col]; // 변경할 위 버튼
					numbtn[row][col].setText(String.valueOf(changebtn.getText())); // 변경할 버튼 입력
					numbtn[row][col].setEnabled(true);

					setrow(row);
					setcol(col);
					row = row - 1; // 위에를 다시 가리킴

					changebtn = numbtn[row][col]; // 빈칸 버튼 지정
					numbtn[row][col].setText("");
					numbtn[row][col].setEnabled(false);

					if (isEnd()) {

						writer.println("[WIN]");

					}
					break;
				}

			case 's':
				if (row == 3) {
					break;
				} else {
					changebtn = numbtn[row + 1][col];
					numbtn[row][col].setText(String.valueOf(changebtn.getText()));
					System.out.println("row : " + row + " col : " + col);
					numbtn[row][col].setEnabled(true);

					setrow(row);
					setcol(col);
					row = row + 1;

					changebtn = numbtn[row][col];
					numbtn[row][col].setText("");
					numbtn[row][col].setEnabled(false);

					if (isEnd()) {

						writer.println("[WIN]");

					}

					break;
				}
			case 'd':
				if (col == 3) {
					break;
				} else {
					changebtn = numbtn[row][col + 1];
					numbtn[row][col].setText(String.valueOf(changebtn.getText()));
					System.out.println("row : " + row + " col : " + col);
					numbtn[row][col].setEnabled(true);

					setrow(row);
					setcol(col);
					col = col + 1;

					changebtn = numbtn[row][col];
					numbtn[row][col].setText("");
					numbtn[row][col].setEnabled(false);

					if (isEnd()) {

						writer.println("[WIN]");

					}
				}
				break;
			case 'a':
				if (col == 0) {
					break;
				} else {
					changebtn = numbtn[row][col - 1];
					numbtn[row][col].setText(String.valueOf(changebtn.getText()));
					System.out.println("row : " + row + " col : " + col);
					numbtn[row][col].setEnabled(true);

					setrow(row);
					setcol(col);
					col = col - 1;

					changebtn = numbtn[row][col];
					numbtn[row][col].setText("");
					numbtn[row][col].setEnabled(false);

					if (isEnd()) {

						writer.println("[WIN]");

					}

					break;
				}
			}
		}

	}

	public int setrow(int row) {
		getrownum = row;
		return getrownum;
	}

	public int getrow() {
		return getrownum;
	}

	public int setcol(int col) {
		getcolnum = col;
		return getcolnum;
	}

	public int getcol() {
		return getcolnum;
	}



	public static String getTimes() {
		return timerBuffer;
	}

	public boolean isRunning() { // 게임의 진행 상태를 반환한다.

		return running;

	}

	public void startGame(String col) { // 게임을 시작한다.

		running = true;

	}

	public void stopGame() { // 게임을 멈춘다.

		writer.println("[STOPGAME]"); // 상대편에게 메시지를 보낸다.

		running = false;

	}

	public void setWriter(PrintWriter writer) {

		this.writer = writer;

	}

}

public class PuzzleClient extends Frame implements Runnable, ActionListener {

	private TextArea msgView = new TextArea("", 1, 1, 1); // 메시지를 보여주는 영역

	private TextField sendBox = new TextField(""); // 보낼 메시지를 적는 상자

	private TextField nameBox = new TextField(); // 사용자 이름 상자

	private TextField roomBox = new TextField(""); // 방 번호 상자

	// 방에 접속한 인원의 수를 보여주는 레이블

	private Label pInfo = new Label("대기실:  명");

	private java.awt.List pList = new java.awt.List(); // 사용자 명단을 보여주는 리스트

	private Button startButton = new Button("게임 시작"); // 시작 버튼

	private Button stopButton = new Button("기권"); // 기권 버튼

	private Button enterButton = new Button("입장하기"); // 입장하기 버튼

	private Button exitButton = new Button("대기실로"); // 대기실로 버튼

	private Button SignUpButton = new Button("회원가입");
	
	private Button RankButton = new Button("랭킹");

	private PuzzleBoard puzzleBoard = new PuzzleBoard(); // Puzzle 화면

	private Ranking_WindowBuilder ranking = new Ranking_WindowBuilder();
	private PuzzleDB Pdb = new PuzzleDB();

	// 각종 정보를 보여주는 레이블

	private Label infoView = new Label("퍼즐 게임", 1);

	private BufferedReader reader; // 입력 스트림

	private PrintWriter writer; // 출력 스트림

	private Socket socket; // 소켓

	private int roomNumber = -1; // 방 번호

	private String userName = null; // 사용자 이름
	
	private static int oldTime; // 타이머 시작 시각을 기억하고 있는 변수
	protected static String timerBuffer; // 경과 시간 문자열이 저장될 버퍼 정의

	public PuzzleClient(String title) { // 생성자

		super(title);

		setLayout(null); // 레이아웃을 사용하지 않는다.

		// 각종 컴포넌트를 생성하고 배치한다.

		msgView.setEditable(false);

		infoView.setBounds(10, 30, 480, 30);

		infoView.setBackground(new Color(200, 200, 255));

		puzzleBoard.setLocation(10, 70);

		add(infoView);

		add(puzzleBoard);

		Panel p = new Panel();

		p.setBackground(new Color(200, 255, 255));

		p.setLayout(new GridLayout(4, 4));

		p.add(new Label("이     름:", 2));
		p.add(nameBox);

		p.add(new Label("방 번호:", 2));
		p.add(roomBox);

		p.add(enterButton);
		p.add(exitButton);
		p.add(SignUpButton);
		p.add(RankButton);

		enterButton.setEnabled(false);

		p.setBounds(500, 30, 250, 70);

		Panel p2 = new Panel();

		p2.setBackground(new Color(255, 255, 100));

		p2.setLayout(new BorderLayout());

		Panel p2_1 = new Panel();

		p2_1.add(startButton);
		p2_1.add(stopButton);

		p2.add(pInfo, "North");
		p2.add(pList, "Center");
		p2.add(p2_1, "South");

		startButton.setEnabled(false);
		stopButton.setEnabled(false);

		p2.setBounds(500, 110, 250, 180);

		Panel p3 = new Panel();

		p3.setLayout(new BorderLayout());

		p3.add(msgView, "Center");

		p3.add(sendBox, "South");

		p3.setBounds(500, 300, 250, 250);

		add(p);
		add(p2);
		add(p3);

		// 이벤트 리스너를 등록한다.

		sendBox.addActionListener(this);

		enterButton.addActionListener(this);

		exitButton.addActionListener(this);

		SignUpButton.addActionListener(this);
		
		RankButton.addActionListener(this);

		startButton.addActionListener(this);

		stopButton.addActionListener(this);

		// 윈도우 닫기 처리

		addWindowListener(new WindowAdapter() {

			public void windowClosing(WindowEvent we) {

				System.exit(0);

			}

		});

	}

	// 컴포넌트들의 액션 이벤트 처리

	public void actionPerformed(ActionEvent ae) {

		if (ae.getSource() == sendBox) { // 메시지 입력 상자이면

			String msg = sendBox.getText();

			if (msg.length() == 0)
				return;

			if (msg.length() >= 30)
				msg = msg.substring(0, 30);

			try {

				writer.println("[MSG]" + msg);

				sendBox.setText("");

			} catch (Exception ie) {
			}

		}

		else if (ae.getSource() == enterButton) { // 입장하기 버튼이면

			try {

				if (Integer.parseInt(roomBox.getText()) < 1) {

					infoView.setText("방번호가 잘못되었습니다. 1이상");

					return;

				}

				writer.println("[ROOM]" + Integer.parseInt(roomBox.getText()));

				msgView.setText("");

			} catch (Exception ie) {

				infoView.setText("입력하신 사항에 오류가 았습니다.");

			}

		}

		else if (ae.getSource() == exitButton) { // 대기실로 버튼이면

			try {

				goToWaitRoom();

				startButton.setEnabled(false);

				stopButton.setEnabled(false);
				
				SignUpButton.setEnabled(false);

			} catch (Exception e) {
			}

		}
		
		else if (ae.getSource() == SignUpButton) { // 회원가입 버튼이면
			
			Login_WindowBuilder login = new Login_WindowBuilder();
			login.frame.setVisible(true); login.frame.setResizable(false);
			
		}
		
		else if (ae.getSource() == RankButton) { // 랭킹 버튼이면
			
			ranking.setVisible(true);
			
		}

		else if (ae.getSource() == startButton) { // 게임 시작 버튼이면
		
			
			
			try {
				
				writer.println("[START]");

				infoView.setText("상대의 결정을 기다립니다.");

				startButton.setEnabled(false);
				
			} catch (Exception e) {
			}
			
		}

		else if (ae.getSource() == stopButton) { // 기권 버튼이면

			try {

				writer.println("[DROPGAME]");

				endGame("기권하였습니다.");

				puzzleBoard.setVisible(false);

			} catch (Exception e) {
			}

		}

	}

	void goToWaitRoom() { // 대기실로 버튼을 누르면 호출된다.

		String name = nameBox.getText().trim();

		LoginDB ldb = new LoginDB();

		System.out.println(ldb.LoginOX(new LoginData(name)));
		if (ldb.LoginOX(new LoginData(name)) == 1) {

			userName = name;

			writer.println("[NAME]" + userName);

			nameBox.setText(userName);

			nameBox.setEditable(false);

			msgView.setText("");

			writer.println("[ROOM]0");

			infoView.setText("대기실에 입장하셨습니다.");

			roomBox.setText("0");

			enterButton.setEnabled(true);

			exitButton.setEnabled(false);

		}

		else {
			JOptionPane.showMessageDialog(null, "등록되지 않은 ID입니다.");
		}

	}

	public void run() {

		String msg; // 서버로부터의 메시지

		try {

			while ((msg = reader.readLine()) != null) {

				if (msg.startsWith("[STONE]")) { // 상대편이 움직인 위치의 좌표

					String temp = msg.substring(7);

					int x = Integer.parseInt(temp.substring(0, puzzleBoard.getrow()));

					int y = Integer.parseInt(temp.substring(0, puzzleBoard.getcol()));

				}

				else if (msg.startsWith("[ROOM]")) { // 방에 입장

					if (!msg.equals("[ROOM]0")) { // 대기실이 아닌 방이면

						enterButton.setEnabled(false);

						exitButton.setEnabled(true);

						infoView.setText(msg.substring(6) + "번 방에 입장하셨습니다.");

					}

					else
						infoView.setText("대기실에 입장하셨습니다.");

					roomNumber = Integer.parseInt(msg.substring(6)); // 방 번호 지정

					if (puzzleBoard.isRunning()) { // 게임이 진행중인 상태이면

						puzzleBoard.stopGame(); // 게임을 중지시킨다.

					}

				}

				else if (msg.startsWith("[FULL]")) { // 방이 찬 상태이면

					infoView.setText("방이 차서 입장할 수 없습니다.");

				}

				else if (msg.startsWith("[PLAYERS]")) { // 방에 있는 사용자 명단

					nameList(msg.substring(9));

				}

				else if (msg.startsWith("[ENTER]")) { // 손님 입장

					pList.add(msg.substring(7));

					playersInfo();

					msgView.append("[" + msg.substring(7) + "]님이 입장하였습니다.\n");

				}

				else if (msg.startsWith("[EXIT]")) { // 손님 퇴장

					pList.remove(msg.substring(6)); // 리스트에서 제거

					playersInfo(); // 인원수를 다시 계산하여 보여준다.

					msgView.append("[" + msg.substring(6) +

							"]님이 다른 방으로 입장하였습니다.\n");

					if (roomNumber != 0)

						endGame("상대가 나갔습니다.");

				}

				else if (msg.startsWith("[DISCONNECT]")) { // 손님 접속 종료

					pList.remove(msg.substring(12));

					playersInfo();

					msgView.append("[" + msg.substring(12) + "]님이 접속을 끊었습니다.\n");

					if (roomNumber != 0)

						endGame("상대가 나갔습니다.");

				}

				else if (msg.startsWith("[READY]")) {
					String str = msg.substring(7);
					puzzleBoard.startGame(str);
					
					if (str.equals("사용자1")) {
						infoView.setText("게임시작");
						puzzleBoard.requestFocus();
						puzzleBoard.setVisible(true);
					} else {
						infoView.setText("게임시작");
						puzzleBoard.requestFocus();
						puzzleBoard.setVisible(true);
					}
					stopwatch(1);
					stopButton.setEnabled(true);
				}

				else if (msg.startsWith("[DROPGAME]")) { // 상대가 기권하면
					
					endGame("상대가 기권하였습니다.");
					puzzleBoard.setVisible(false);
				}

				else if (msg.startsWith("[WIN]")) { // 이겼으면
					stopwatch(0);
					endGame("이겼습니다.");
					puzzleBoard.setVisible(false);
					Pdb.InsertPuzzleDB(new PuzzleData(nameBox.getText().trim(), getTimes()));
					ranking.select(); // 중첩으로 나옴 변경해야됨
				}

				else if (msg.startsWith("[LOSE]")) { // 졌으면

					endGame("졌습니다.");
					puzzleBoard.setVisible(false);
				}

				// 약속된 메시지가 아니면 메시지 영역에 보여준다.

				else
					msgView.append(msg + "\n");

			}

		} catch (IOException ie) {

			msgView.append(ie + "\n");

		}

		msgView.append("접속이 끊겼습니다.");
		

	}

	private void endGame(String msg) { // 게임의 종료시키는 메소드

		infoView.setText(msg);

		startButton.setEnabled(false);

		stopButton.setEnabled(false);

		try {
			Thread.sleep(2000);
		} catch (Exception e) {
		} // 2초간 대기

		if (puzzleBoard.isRunning())
			puzzleBoard.stopGame();

		if (pList.getItemCount() == 2)
			startButton.setEnabled(true);

	}

	private void playersInfo() { // 방에 있는 접속자의 수를 보여준다.

		int count = pList.getItemCount();

		if (roomNumber == 0)

			pInfo.setText("대기실: " + count + "명");

		else
			pInfo.setText(roomNumber + " 번 방: " + count + "명");

		// 대국 시작 버튼의 활성화 상태를 점검한다.

		if (count == 2 && roomNumber != 0)

			startButton.setEnabled(true);

		else
			startButton.setEnabled(false);

	}

	// 사용자 리스트에서 사용자들을 추출하여 pList에 추가한다.

	private void nameList(String msg) {

		pList.removeAll();

		StringTokenizer st = new StringTokenizer(msg, "\t");

		while (st.hasMoreElements())

			pList.add(st.nextToken());

		playersInfo();

	}

	private void connect() { // 연결

		try {

			msgView.append("서버에 연결을 요청합니다.\n");

			socket = new Socket("127.0.0.1", 7777);

			msgView.append("---연결 성공--.\n");

			msgView.append("이름을 입력하고 대기실로 입장하세요.\n");

			reader = new BufferedReader(

					new InputStreamReader(socket.getInputStream()));

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

			new Thread(this).start();

			puzzleBoard.setWriter(writer);

		} catch (Exception e) {

			msgView.append(e + "\n\n연결 실패..\n");

		}
		
		

	}
	
	
	public static void stopwatch(int onOff) {
		if (onOff == 1) // 타이머 on
			oldTime = (int) System.currentTimeMillis() / 1000;

		if (onOff == 0) // 타이머 off, 시분초 timerBuffer 에 저장
			secToHHMMSS(((int) System.currentTimeMillis() / 1000) - oldTime);

	}

	// 정수로 된 시간을 초단위(sec)로 입력 받고, 문자열로 시분초를 저장
	public static void secToHHMMSS(int secs) {
		int hour, min, sec;

		sec = secs % 60;
		min = secs / 60 % 60;
		hour = secs / 3600;

		timerBuffer = String.format("%02d%02d%02d", hour, min, sec);
		System.out.println(timerBuffer);
	}
	
	public static String getTimes() {
		return timerBuffer;
	}

	public static void main(String[] args) {

		PuzzleClient client = new PuzzleClient("네트워크 퍼즐게임");

		client.setSize(760,560);

		client.setVisible(true);

		client.connect();

	}

}

Server

package Socket_pkg;

import java.net.*;

import java.io.*;

import java.util.*;

public class PuzzleServer {

	private ServerSocket server;

	private BManager bMan = new BManager(); // 메시지 방송자

	private Random rnd = new Random();

	public PuzzleServer() {
	}

	void startServer() { // 서버를 실행한다.

		try {

			server = new ServerSocket(7777);

			System.out.println("서버소켓이 생성되었습니다.");

			while (true) {

				// 클라이언트와 연결된 스레드를 얻는다.

				Socket socket = server.accept();

				// 스레드를 만들고 실행시킨다.

				Puzzle_Thread ot = new Puzzle_Thread(socket);

				ot.start();

				// bMan에 스레드를 추가한다.

				bMan.add(ot);

				System.out.println("접속자 수: " + bMan.size());

			}

		} catch (Exception e) {

			System.out.println(e);

		}

	}

	// 클라이언트와 통신하는 스레드 클래스

	class Puzzle_Thread extends Thread {

		private int roomNumber = -1; // 방 번호

		private String userName = null; // 사용자 이름

		private Socket socket; // 소켓

		// 게임 준비 여부, true이면 게임을 시작할 준비가 되었음을 의미한다.

		private boolean ready = false;

		private BufferedReader reader; // 입력 스트림

		private PrintWriter writer; // 출력 스트림

		Puzzle_Thread(Socket socket) { // 생성자

			this.socket = socket;

		}

		Socket getSocket() { // 소켓을 반환한다.

			return socket;

		}

		int getRoomNumber() { // 방 번호를 반환한다.

			return roomNumber;

		}

		String getUserName() { // 사용자 이름을 반환한다.

			return userName;

		}

		boolean isReady() { // 준비 상태를 반환한다.

			return ready;

		}

		public void run() {

			try {

				reader = new BufferedReader(

						new InputStreamReader(socket.getInputStream()));

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

				String msg; // 클라이언트의 메시지

				while ((msg = reader.readLine()) != null) {

					// msg가 "[NAME]"으로 시작되는 메시지이면

					if (msg.startsWith("[NAME]")) {

						userName = msg.substring(6); // userName을 정한다.

					}

					// msg가 "[ROOM]"으로 시작되면 방 번호를 정한다.

					else if (msg.startsWith("[ROOM]")) {

						int roomNum = Integer.parseInt(msg.substring(6));

						if (!bMan.isFull(roomNum)) { // 방이 찬 상태가 아니면

							// 현재 방의 다른 사용에게 사용자의 퇴장을 알린다.

							if (roomNumber != -1)

								bMan.sendToOthers(this, "[EXIT]" + userName);

							// 사용자의 새 방 번호를 지정한다.

							roomNumber = roomNum;

							// 사용자에게 메시지를 그대로 전송하여 입장할 수 있음을 알린다.

							writer.println(msg);

							// 사용자에게 새 방에 있는 사용자 이름 리스트를 전송한다.

							writer.println(bMan.getNamesInRoom(roomNumber));

							// 새 방에 있는 다른 사용자에게 사용자의 입장을 알린다.

							bMan.sendToOthers(this, "[ENTER]" + userName);

						}

						else
							writer.println("[FULL]"); // 사용자에 방이 찼음을 알린다.

					}

					// "[STONE]" 메시지는 상대편에게 전송한다.

					else if (roomNumber >= 1 && msg.startsWith("[STONE]"))

						bMan.sendToOthers(this, msg);

					// 대화 메시지를 방에 전송한다.

					else if (msg.startsWith("[MSG]"))

						bMan.sendToRoom(roomNumber,

								"[" + userName + "]: " + msg.substring(5));

					// "[START]" 메시지이면

					else if (msg.startsWith("[START]")) {

						ready = true; // 게임을 시작할 준비가 되었다.

						// 다른 사용자도 게임을 시작한 준비가 되었으면

						if (bMan.isReady(roomNumber)) {

							int a = rnd.nextInt(2);

							if (a == 0) {
								writer.println("[READY]사용자1");

								bMan.sendToOthers(this, "[READY]사용자2");
							}

							else {
								writer.println("[READY]사용자2");

								bMan.sendToOthers(this, "[READY]사용자1");
							}

						}

					}

					// 사용자가 게임을 중지하는 메시지를 보내면

					else if (msg.startsWith("[STOPGAME]"))

						ready = false;

					// 사용자가 게임을 기권하는 메시지를 보내면

					else if (msg.startsWith("[DROPGAME]")) {

						ready = false;

						// 상대편에게 사용자의 기권을 알린다.

						bMan.sendToOthers(this, "[DROPGAME]");

					}

					// 사용자가 이겼다는 메시지를 보내면

					else if (msg.startsWith("[WIN]")) {

						ready = false;

						// 사용자에게 메시지를 보낸다.

						writer.println("[WIN]");

						// 상대편에는 졌음을 알린다.

						bMan.sendToOthers(this, "[LOSE]");

					}

				}

			} catch (Exception e) {

			} finally {

				try {

					bMan.remove(this);

					if (reader != null)
						reader.close();

					if (writer != null)
						writer.close();

					if (socket != null)
						socket.close();

					reader = null;
					writer = null;
					socket = null;

					System.out.println(userName + "님이 접속을 끊었습니다.");

					System.out.println("접속자 수: " + bMan.size());

					// 사용자가 접속을 끊었음을 같은 방에 알린다.

					bMan.sendToRoom(roomNumber, "[DISCONNECT]" + userName);

				} catch (Exception e) {
				}

			}

		}

	}

	class BManager extends Vector { // 메시지를 전달하는 클래스

		BManager() {
		}

		void add(Puzzle_Thread ot) { // 스레드를 추가한다.

			super.add(ot);

		}

		void remove(Puzzle_Thread ot) { // 스레드를 제거한다.

			super.remove(ot);

		}

		Puzzle_Thread getOT(int i) { // i번째 스레드를 반환한다.

			return (Puzzle_Thread) elementAt(i);

		}

		Socket getSocket(int i) { // i번째 스레드의 소켓을 반환한다.

			return getOT(i).getSocket();

		}

		// i번째 스레드와 연결된 클라이언트에게 메시지를 전송한다.

		void sendTo(int i, String msg) {

			try {

				PrintWriter pw = new PrintWriter(getSocket(i).getOutputStream(), true);

				pw.println(msg);

			} catch (Exception e) {
			}

		}

		int getRoomNumber(int i) { // i번째 스레드의 방 번호를 반환한다.

			return getOT(i).getRoomNumber();

		}

		synchronized boolean isFull(int roomNum) { // 방이 찼는지 알아본다.

			if (roomNum == 0)
				return false; // 대기실은 차지 않는다.

			// 다른 방은 2명 이상 입장할 수 없다.

			int count = 0;

			for (int i = 0; i < size(); i++)

				if (roomNum == getRoomNumber(i))
					count++;

			if (count >= 2)
				return true;

			return false;

		}

		// roomNum 방에 msg를 전송한다.

		void sendToRoom(int roomNum, String msg) {

			for (int i = 0; i < size(); i++)

				if (roomNum == getRoomNumber(i))

					sendTo(i, msg);

		}

		// ot와 같은 방에 있는 다른 사용자에게 msg를 전달한다.

		void sendToOthers(Puzzle_Thread ot, String msg) {

			for (int i = 0; i < size(); i++)

				if (getRoomNumber(i) == ot.getRoomNumber() && getOT(i) != ot)

					sendTo(i, msg);

		}

		// 게임을 시작할 준비가 되었는가를 반환한다.

		// 두 명의 사용자 모두 준비된 상태이면 true를 반환한다.

		synchronized boolean isReady(int roomNum) {

			int count = 0;

			for (int i = 0; i < size(); i++)

				if (roomNum == getRoomNumber(i) && getOT(i).isReady())

					count++;

			if (count == 2)
				return true;

			return false;

		}

		// roomNum방에 있는 사용자들의 이름을 반환한다.

		String getNamesInRoom(int roomNum) {

			StringBuffer sb = new StringBuffer("[PLAYERS]");

			for (int i = 0; i < size(); i++)

				if (roomNum == getRoomNumber(i))

					sb.append(getOT(i).getUserName() + "\t");

			return sb.toString();

		}

	}

	public static void main(String[] args) {

		PuzzleServer server = new PuzzleServer();

		server.startServer();

	}

}

실행결과

서버 생성 후 접속자 연결
Client GUI 화면
이름 입력 후 대기실 버튼 클릭 화면
방 입장 후 게임 시작 화면


Part 1. 로그인 바로가기
Part 2. 퍼즐 바로가기
Part 3. 랭킹 바로가기

전체 소스코드 바로가기

 

 

참고 바로가기

랭킹파트도 동일하게 소켓통신을 사용하지 않은 슬라이딩 퍼즐게임과 동일하게 변경되지 않았으므로, 설명은 생략하겠습니다.

 

슬라이딩 퍼즐 게임 Part 3. 랭킹 바로가기


Ranking WindowBuilder

package Ranking_pkg;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Font;
import java.util.Vector;

import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;

import Puzzle_pkg.PuzzleData;
import Puzzle_pkg.PuzzleDB;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class Ranking_WindowBuilder extends JFrame {

	private JTable table;
	
	String colNames[] = {"Rank","ID","Time"};
	private DefaultTableModel model = new DefaultTableModel(colNames, 0);

	public Ranking_WindowBuilder() {  // 생성자
		initialize();
		select();
		KeyF5();
	}
	
	PuzzleDB db = new PuzzleDB();

	public void select() {  // 랭킹 정보 출력
			Vector<PuzzleData> Ar = new Vector<PuzzleData>();
			Ar = db.PuzzleDBlist();
			model.setRowCount(0);
			for(int i=0; i< Ar.size();i++)
			{
				model.setRowCount(0);
				model.addRow(new Object[]{Ar.get(i).GetID(),Ar.get(i).GetTime(),Ar.get(i).GetRank()});
			}	
			
	}
	
	public void KeyF5(){  // F5 클릭 시 새로고침
		addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				int keyCode = e.getKeyCode();

				if(keyCode==KeyEvent.VK_F5) 
				{
					model.setRowCount(0);
					select();
					
				}
			}
		});
		setFocusable(true);
		requestFocus();
	}
	
	
	private void initialize() {
		setBounds(100, 100, 460, 416);
		getContentPane().setLayout(null);
		
		JPanel panel = new JPanel();
		panel.setBackground(Color.WHITE);
		panel.setBounds(0, 0, 442, 377);
		getContentPane().add(panel);
		panel.setLayout(null);
		
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setFont(new Font("함초롱바탕", Font.PLAIN, 18));
		scrollPane.setBounds(0, 0, 442, 377);
		panel.add(scrollPane);
		
		table = new JTable(model){
			public boolean isCellEditable(int row, int column) { // 클릭 비활성화
		        return false;
			}
		};

		table.setBackground(Color.WHITE);
		table.setFont(new Font("함초롱바탕", Font.PLAIN, 16));
		
		//테이블 가운데 정렬
		DefaultTableCellRenderer cell = new DefaultTableCellRenderer();
		cell.setHorizontalAlignment(SwingConstants.CENTER);
		TableColumnModel centerModel = table.getColumnModel();
		for(int i=0;i < centerModel.getColumnCount(); i++) centerModel.getColumn(i).setCellRenderer(cell);
		
		//테이블 컬럼의 이동을 방지
				table.getTableHeader().setReorderingAllowed(false);      
				table.getColumnModel().getColumn(0).setPreferredWidth(20);
				table.getColumnModel().getColumn(0).setResizable(false);
				table.getColumnModel().getColumn(1).setPreferredWidth(162);
				
		scrollPane.setViewportView(table);

	}
}

실행화면

랭킹 실행화면

 

다음으로 소켓통신 슬라이딩 퍼즐의 소켓통신에 대한 설명은 Part 4. 소켓통신에서 하도록 하겠습니다.


 

Part 1. 로그인 바로가기
Part 2. 퍼즐 바로가기
Part 4. 소켓통신 바로가기

전체 소스코드 바로가기

 

앞서 소켓통신을 사용하지 않은 슬라이딩 퍼즐게임과 동일하게 퍼즐 파트는 변경되지 않았으므로, 설명은 생략하겠습니다.

 

슬라이딩 퍼즐 Part 2. 퍼즐 바로가기


Puzzle DTO

package Puzzle_pkg;


public class PuzzleData {
	private String ID,Time,Rank;
	public PuzzleData() {}
	public PuzzleData(String ID, String Time){
		this.ID = ID;
		this.Time = Time;
	}
	
	public PuzzleData(String ID, String Time, String Rank){
		this.ID = ID;
		this.Time = Time;
		this.Rank = Rank;
	}
	
	public PuzzleData(String ID){
		this.ID = ID;
	}
	
	
	public String GetID(){
		return ID;
	}
	public void SetID(String ID){
		this.ID = ID;
	}
	public String GetTime(){
		return Time;
	}
	public void SetTime(String Rank){
		this.Time = Rank;
	}
	public String GetRank(){
		return Rank;
	}
	public void SetRank(String Rank){
		this.Rank = Rank;
	}
	
}

Puzzle DAO

package Puzzle_pkg;

import java.util.*;
import java.sql.*;

public class PuzzleDB{
	Connection conn = null;
	ResultSet rs = null;
	Statement st = null;
	PreparedStatement ps = null;
	
	public PuzzleDB() { // 생성자로 데이터베이스 연결
		try {
			final String url = "jdbc:mariadb://localhost:3306/puzzledb";
			final String id = "root";
			final String pw = "1234";
			
			Class.forName("org.mariadb.jdbc.Driver");
			conn = DriverManager.getConnection(url, id, pw);
			
		}catch(ClassNotFoundException cnfe) {
			System.out.println("DB 드라이버 로딩 실패:"+ cnfe.toString());
		}catch(SQLException sqle){
			System.out.println("DB 접속실패"+ sqle.toString());
		}catch(Exception e){
			System.out.println("Unkown error");
			e.printStackTrace();
		}
	}
	
	public void DBClose() { // 커넥션 연결 종료
		try {
			if(rs != null) rs.close();
			if(st != null) st.close();
			if(ps != null) ps.close();
		} catch (Exception e) {
			System.out.println(e + " => DBClose fail");
		}
	}
	
	//퍼즐 정보 저장
	public void InsertPuzzleDB(PuzzleData puzzledata) { // puzzle table -> puzzle data insert
		try {
			String sql = "insert into puzzle values(?, ?, ?)";
			ps = conn.prepareStatement(sql);
			ps.setString(1, puzzledata.GetID());
			ps.setString(2, puzzledata.GetTime());
			ps.setString(3, null);
			ps.executeUpdate();
		} catch(SQLException e) {
			e.printStackTrace();
		} finally {
			DBClose();
		}
	}
	
	//퍼즐 정보 리스트
	public Vector<PuzzleData> PuzzleDBlist() // puzzle table -> puzzle data list
	{
		Vector<PuzzleData> Ar = new Vector<PuzzleData>();
		 
		 try{
			 st = conn.createStatement();
			 
			 String sql = "Select DENSE_RANK() OVER (ORDER BY Time ASC ) as RANK, ID, Time from puzzle";
			 rs = st.executeQuery(sql);
			 while (rs.next()) {
				 Ar.add(new PuzzleData(rs.getString(1), rs.getString(2), rs.getString(3)));
			 }
		 }catch (SQLException e) {
				e.printStackTrace();
			} finally {
				DBClose();
			}
		 return Ar;
		 
	}
	
	// 퍼즐 정보 업데이트
	public void UpdatePuzzleDB(PuzzleData puzzledata) // puzzle table -> puzzle data update
	{
		try {
			String Updata = "update puzzle set Rank = ?, where Time = ?;";
			ps = conn.prepareStatement(Updata);
			ps.setString(1, puzzledata.GetRank());
			ps.setString(2, puzzledata.GetTime());
			ps.executeUpdate();
			}catch(SQLException e){	
				e.printStackTrace();
			} finally {
				DBClose();
			}
	}

	// 퍼즐 정보 삭제
	public void Delete(String ID) // puzzle table -> puzzle data delete
	{
		String Delete = "delete from puzzle where ID = ?;";
		try {
			ps = conn.prepareStatement(Delete);
			ps.setString(1, ID);
			ps.executeUpdate();
		}catch (SQLException e) {
			e.printStackTrace();
		} finally {
				DBClose();
		}	
	}
}

 

다음으로 소켓통신 슬라이딩 퍼즐의 랭킹에 대한 설명은 Part 3. 랭킹에서 하도록 하겠습니다.

 


Part 1. 로그인 바로가기
Part 3. 랭킹 바로가기
Part 4. 소켓통신 바로가기

 

전체 소스코드 바로가기

앞서 슬라이딩 퍼즐 게임(로그인, 퍼즐 GUI, 랭킹 GUI)를 만들었고, 소켓 통신과 연결을 하였습니다.

앞서 만들어둔 슬라이딩 퍼즐 게임과 변경된 점, 추가된 코드를 설명하였습니다.

 

로그인 DAO, DTO 는 동일하게 사용했으므로 설명 생략하도록 하겠습니다.

 

슬라이딩 퍼즐 게임 Part 1. 로그인 바로가기


로그인 DTO

package Login_pkg;

public class LoginData {
	private String ID;
	private String Password;
	public LoginData() { }
	public LoginData(String ID, String Password){
		this.ID = ID;
		this.Password = Password;
		System.out.println("ID"+ID);
	}
	
	public LoginData(String ID){
		this.ID = ID;
	}
	
	public String GetID(){
		return ID;
	}
	public void SetID(String Password){
		this.Password = Password;
	}
	public String GetPassword(){
		return Password;
	}
	public void SetPasswordD(String Password){
		this.Password = Password;
	}

로그인 DAO

package Login_pkg;

import java.sql.*;

public class LoginDB {
	private Connection conn = null;
	private ResultSet rs = null;
	private Statement st = null;
	private PreparedStatement ps = null;
	int count = 0;
	
	
	public LoginDB() { // 생성자로 데이터 베이스 연결
		
		final String url = "jdbc:mariadb://localhost:3306/puzzledb";
		final String id = "root";
		final String pw = "1234";
		try{
		Class.forName("org.mariadb.jdbc.Driver");
		conn = DriverManager.getConnection(url, id, pw);
		}catch(ClassNotFoundException cnfe) {
			System.out.println("DB 드라이버 로딩 실패:"+ cnfe.toString());
		}catch(SQLException sqle){
			System.out.println("DB 접속실패"+ sqle.toString());
		}catch(Exception e){
			System.out.println("Unkown error");
			e.printStackTrace();
		}	
	}

	
	public void DBClose(){ // 커넥션 연결 종료
		try{
			if(rs != null) rs.close();
			if(st != null) st.close();
			if(ps != null) ps.close();
		}catch(Exception e) { System.out.println(e + "=> DBClose 실패");}
	}
	
	// 회원 정보 저장
	public void InsertLogin(LoginData logindata){  // login table -> Login data insert
		String sql = "insert into login values(?, ?, ?)";
		
		try{
			ps = conn.prepareStatement(sql);
			st = conn.createStatement();
			rs = st.executeQuery("Select * From login order by position*1");
			while(rs.next())
			{
				int Number1 = rs.getInt("position");
				if(Number1 == count) count++;
				}
			ps.setInt(1, count);
			ps.setString(2, logindata.GetID());
			ps.setString(3, logindata.GetPassword());
			ps.executeUpdate();
			count++;
		}catch(SQLException e) 
		{
			e.printStackTrace();
		}finally 
		{
			DBClose();
		}
	}
	
	// 회원 정보 삭제
	public void Delete(String ID){  // login table -> Login data delete
		String sql = "Delete from login where ID =?";
		
		try{
			ps = conn.prepareStatement(sql);
			ps.setString(1, ID);
			ps.executeUpdate();
		}catch(SQLException e)
		{	
			e.printStackTrace();
		} finally 
		{
			DBClose();
		}
	}
	
	// ID, Password 확인
	public int LoginTry(LoginData logindata){ // login table -> Login ID, Password Confirm
		String sql = "select * from login where ID = ? and Password = ?";
		
		try{
		ps = conn.prepareStatement(sql);
		ps.setString(1, logindata.GetID());
		ps.setString(2, logindata.GetPassword());
		rs = ps.executeQuery();
		
		if(rs.next())
		{
			return 1;		
		}	
		}catch(Exception e) 
		{
			e.printStackTrace();
		}
		return -1;
	}
	
	// ID 확인
	public int LoginOX(LoginData logindata){ // login_management table -> Login ID Confirm
		String sql = "select * from login where ID = ?";
		try{
		ps = conn.prepareStatement(sql);
		ps.setString(1, logindata.GetID());
		rs = ps.executeQuery();
		if(rs.next()) 
		{
			return 1;
		}
		
		}catch(Exception e)
		{ 
			e.printStackTrace();
		}
		return -1;
	}

}

로그인 WindowBuilder

package Login_pkg;


import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

import java.awt.Color;

public class Login_WindowBuilder {

	public JFrame frame;
	private JTextField IDtext;
	private JPasswordField passwordtext;
	private String getID = "" , getPS = "";
	
	private LoginDB Ldb = new LoginDB();

	/* main client 클래스로 변경
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() { 
			public void run() {
				try {
					Login_WindowBuilder window = new Login_WindowBuilder();
					window.frame.setVisible(true);
					window.frame.setResizable(false);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
    */

	public Login_WindowBuilder() 
	{
		initialize();
	}
	private void initialize() {
		frame = new JFrame();
		frame.setBounds(100, 100, 401, 346);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().setLayout(null);
		
		JPanel panel = new JPanel();
		panel.setBackground(Color.WHITE);
		panel.setBounds(0, 0, 385, 307);
		frame.getContentPane().add(panel);
		panel.setLayout(null);
		
		JLabel IDLabel = new JLabel("ID : ");
		IDLabel.setBounds(71, 122, 66, 33);
		IDLabel.setHorizontalAlignment(SwingConstants.CENTER);
		IDLabel.setFont(new Font("맑은 고딕", Font.BOLD, 18));
		panel.add(IDLabel);
		
		JLabel PassWordLabel = new JLabel("PW : ");
		PassWordLabel.setBounds(71, 173, 66, 29);
		PassWordLabel.setHorizontalAlignment(SwingConstants.CENTER);
		PassWordLabel.setFont(new Font("맑은 고딕", Font.BOLD, 18));
		panel.add(PassWordLabel);
		
		IDtext = new JTextField();
		IDtext.setBounds(149, 125, 145, 33);
		IDtext.setToolTipText("ID 입력");
		panel.add(IDtext);
		IDtext.setColumns(10);
		
		passwordtext = new JPasswordField();
		passwordtext.setBounds(149, 172, 145, 33);
		passwordtext.setToolTipText("PassWord 입력");
		panel.add(passwordtext);
		
		JLabel lblNewLabel = new JLabel("로그인 창");
		lblNewLabel.setBounds(12, 10, 361, 81);
		lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
		lblNewLabel.setFont(new Font("돋움체", Font.BOLD, 30));
		panel.add(lblNewLabel);
		
		JButton Loginbutton = new JButton("로그인");
		Loginbutton.setVisible(false);
		Loginbutton.setBackground(Color.WHITE);
		Loginbutton.setBounds(71, 243, 111, 47);
		Loginbutton.addActionListener(new ActionListener() { // 로그인 버튼 클릭 시 동작
			public void actionPerformed(ActionEvent arg0) {
				String ID = IDtext.getText();
				char[] PS1 = passwordtext.getPassword();
				
				String PS = String.valueOf(PS1);
				
				getID = ID; getPS = PS;

				int s = Ldb.LoginTry(new LoginData(ID,PS));
				
				if(s == 1) {
				
				JOptionPane.showMessageDialog(null, "로그인 성공");
				frame.dispose(); // 로그인 GUI 창 종료
                
                /* client 클래스에서 실행
                Puzzle_Swing window = new Puzzle_Swing();
				window.setVisible(true); // 슬라이딩 퍼즐 GUI 화면 나타남
				window.setResizable(false);  // GUI 창 크기 조절 불가능
				Ranking window2  =  new Ranking();
				window2.frame.setVisible(true); // 랭킹 GUI 화면 나타남
				window2.frame.setResizable(false);  // GUI 창 크기 조절 불가능
                */
				
				} else JOptionPane.showMessageDialog(null, "로그인 실패");
				
				
			}
		});
		Loginbutton.setFont(new Font("맑은 고딕", Font.PLAIN, 15));
		panel.add(Loginbutton);
		
		JButton button = new JButton("회원 가입");
		button.setBackground(Color.WHITE);
		button.setBounds(211, 243, 111, 47);
		button.addActionListener(new ActionListener() { // 회원 가입 버튼 클릭 시 동작
			public void actionPerformed(ActionEvent e) {
				
				String ID = IDtext.getText();
				char[] PS1 = passwordtext.getPassword();
				String PS = String.valueOf(PS1);
				
				
				if(ID.length() != 0 && PS.length() != 0)
				{
				Ldb.InsertLogin(new LoginData(ID, PS));
				IDtext.setText(""); passwordtext.setText("");
				JOptionPane.showMessageDialog(null, "등록 완료");
				frame.dispose(); 
				
				}
				else JOptionPane.showMessageDialog(null, "ID , PW 입력 바람.");
			}
		});
		button.setFont(new Font("맑은 고딕", Font.PLAIN, 15));
		panel.add(button);
	}

	public String getID() {
		return getID;
	}
	public String getPassword() {
		
		return getPS;
	}
}

이전 슬라이딩 퍼즐 게임에서는 해당 클래스파일에서 main 메소드를 실행 시켰지만, 소켓 통신을 연결함으로 써, client에서 main 메소드를 실행시킨다. 퍼즐 GUI 또한 client에 구현하였고, Puzzle_Swing 클래스도 필요없어지게 되었습니다.

또한 로그인 부분도 client에서 하기때문에  setVisible(false)를 주어 버튼을 나타나지 않도록 하였습니다.


실행결과

로그인 실행화면

 

 

다음으로 소켓통신 슬라이딩 퍼즐의 퍼즐에 대한 설명은 Part 2. 퍼즐에서 하도록 하겠습니다.


Part 2. 퍼즐 바로가기

Part 3. 랭킹 바로가기

Part 4. 소켓통신 바로가기

 

전체 소스코드 바로가기

+ Recent posts