소켓 통신을 하기위하여 기본적인 라이브러리 추가 방법을 모른다면 이전 글을 참조해주세요

 

위 이미지처럼 결과가 나오게끔 코드를 공개하겠습니다.

 

클라이언트 코드

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS

#include <WinSock2.h>
#include <stdlib.h>
#include <stdio.h>

#define BUFSIZE 512

int main(int argc, char* argv[]) {
	int retval;

	// 윈속 초기화
	WSADATA wsa;
	if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
		return -1;

	// socket()
	SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock == INVALID_SOCKET) return -1;
	printf("UDP 소켓이 생성되었습니다.\n");

	// 소켓 주소 구조체 초기화
	SOCKADDR_IN serveraddr;
	ZeroMemory(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(9000);
	serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	// 데이터 통신에 사용할 변수
	SOCKADDR_IN peeraddr;
	int addrlen;
	char buf[BUFSIZE + 1];
	int len;
	for (int i = 0; i < 5; i++) {
		// 데이터 입력
		printf("\n[보낼 데이터]");
		fgets(buf, BUFSIZE + 1, stdin); // buf 에 BUFSIZE +1 만큼의 크기를 입력 buf는 배열의 시작 주소를 가르킨다. 
		// 배열의 이름 = 배열의 시작 주소
		//stdin -> 키보드 입력 사용

		// '\n' 문자 제거
		len = strlen(buf);
		if (buf[len - 1] == '\n')
			buf[len - 1] = '\0';

		// printf("buf: %s\n", buf);


			// 데이터 보내기
		retval = sendto(sock, buf, strlen(buf), 0, (SOCKADDR*)&serveraddr, sizeof(serveraddr));
		if (retval == SOCKET_ERROR) return -1;
		printf("[클라이언트] %d바이트를 보냈습니다.\n", retval);

		// 데이터 받기
		addrlen = sizeof(peeraddr);
		retval = recvfrom(sock, buf, BUFSIZE, 0,
			(SOCKADDR*)&peeraddr, &addrlen);
		printf("서버로 부터 데이터를 받았습니다. \n\n");

		// 송신자의 IP 주소 체크
		if (memcmp(&peeraddr, &serveraddr, sizeof(peeraddr)))
		{
			printf("[오류] 잘못된 데이터 입니다!\n");
			return -1;
		}

		//받은 데이터 출력
		buf[retval] = '\0';
		printf("[클라이언트] %d바이트를 받았습니다.\n", retval);
		printf("[받은 데이터] %s\n", buf);
	}

	// closesocket()
	closesocket(sock);

	// 윈속 종료
	WSACleanup();
	return 0;
}

 

서버 코드

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS

#include <WinSock2.h>
#include <stdlib.h>
#include <stdio.h>


#define BUFSIZE 512

int main(int argc, char* argv[])
{
	int retval;

	// 윈속 초기화
	WSADATA wsa;
	if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
		return -1;

	// socket()
	SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock == INVALID_SOCKET) return -1;
	printf("UDP 소켓이 생성되었습니다.\n");

	// bind()
	SOCKADDR_IN serveraddr;
	ZeroMemory(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(9000); // host(컴퓨터가 데이터 읽는 방식) 방식을 network방식으로 변경
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
	retval = bind(sock, (SOCKADDR*)&serveraddr, sizeof(serveraddr));

	if (retval == SOCKET_ERROR) return -1;
	printf("Bind 완료 되었습니다.\n");

	//데이터 통신에 사용할 변수
	SOCKADDR_IN clientaddr;
	int addrlen;
	char buf[BUFSIZE + 1];

	for (int i = 0; i < 5; i++) {
		// 데이터 받기
		addrlen = sizeof(clientaddr);
		retval = recvfrom(sock, buf, BUFSIZE, 0,
			(SOCKADDR*)&clientaddr, &addrlen);
		printf("Client로 부터 데이터를 받았습니다.\n");

		// 받은 데이터 출력
		buf[retval] = '\0';
		printf("[UDP/%s:%d] %s\n", inet_ntoa(clientaddr.sin_addr),
			ntohs(clientaddr.sin_port), buf);

		// 데이터 보내기
		retval = sendto(sock, buf, retval, 0,
			(SOCKADDR*)&clientaddr, sizeof(clientaddr));
		printf("Client로 데이터를 전송했습니다.");
	}

	// closesocket()
	closesocket(sock);

	// 윈속 종료
	WSACleanup();
	return 0;
}

우선 소켓 통신을 하기에 앞서 사용해야할 라이브러리를 사용할 수 있도록 설정하겠습니다.

 

비주얼 스튜디오 프로젝트 생성을 했다면, 우측 상단 탭에서 프로젝트 -> 속성 클릭

구성속성 -> 고급에서

문자 집합을 멀티바이트 문자 집합 사용으로 변경

 

다음으로, 링커 -> 입력으로 들어가 추가 종속성을 추가한다.

 

라이브러리를 추가하는 방식이 번거롭다면 임의 위치에 아래 코드를 넣어서 사용해도 됩니다.

#pragma comment(lib, "ws2_32");

를 넣어주면 소켓 통신 기본 준비는 끝납니다.

 

서버와 클라이언트는 각각의 프젝트로 생성하는 것을 추천드립니다.

 

 

서버 소스코드

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS

#include <winsock2.h>
#include<stdio.h>
#include<stdlib.h>
#pragma comment(lib, "ws2_32");

#define BUFSIZE 512

void err_quit(const char* msg) {
	LPVOID IpMsgBuf;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
		NULL, WSAGetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR)&IpMsgBuf, 0, NULL);
	exit(-1);

}

int main(int argc, char* argv[]) {
	int retval;

	//원속초기화
	WSADATA wsa;
	if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
		return -1;
	//MessageBox(NULL, "원속 초기화 성공", "알림", MB_OK);

	//socket()
	SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, 0);
	if (listen_sock == INVALID_SOCKET) err_quit("socket()");
	printf("소켓이 생성되었습니다\n");
	//MessageBox(NULL, "TCP 소켓성공", "알림", MB_OK);

	//bind()
	SOCKADDR_IN serveraddr;
	ZeroMemory(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
	serveraddr.sin_port = htons(9000);

	bind(listen_sock, (SOCKADDR*)&serveraddr, sizeof(serveraddr));
	printf("Bind 완료 되었습니다.\n");

	//listen()
	listen(listen_sock, SOMAXCONN);
	printf("connect 연결을 기다리는 중..\n");

	//통신에 사용할 변수
	SOCKET client_sock;
	SOCKADDR_IN clientaddr;
	int addrlen;
	char buf[BUFSIZE + 1];

	//accept()
	addrlen = sizeof(clientaddr);
	client_sock = accept(listen_sock, (SOCKADDR*)&clientaddr, &addrlen);
	printf("요청을 받았습니다.\n");

	//recv()
	retval = recv(client_sock, buf, BUFSIZE, 0);
	printf("메세지를 수신하였습니다.\n");

	//받는 데이터 출력
	buf[retval] = '\0';
	printf("[TCP/%s:%d] %s\n",
		inet_ntoa(clientaddr.sin_addr),
		ntohs(clientaddr.sin_port), buf);
	//closesocket
	closesocket(listen_sock);

	//원속 종료
	WSACleanup();
	return 0;

}

 

클라이언트 소스코드

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32");

#define BUFSIZE 512

void err_quit(const char* msg) {
	LPVOID IpMsgBuf;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
		NULL, WSAGetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR)&IpMsgBuf, 0, NULL);
	exit(-1);

}

int main(int argc, char* argv[]) {
	//원속 초기화
	WSADATA wsa;
	if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
		return -1;
	//MessageBox(NULL, "원속 초기화 성공", "알림", MB_OK);

	//socket()
	SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock == INVALID_SOCKET) err_quit("socket()");
	printf("소켓이 생성되었습니다.\n");
	//MessageBox(NULL, "TCP 소켓성공", "알림", MB_OK);

	//connect()
	SOCKADDR_IN serveraddr;
	ZeroMemory(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	serveraddr.sin_port = htons(9000);

	connect(sock, (SOCKADDR*)&serveraddr, sizeof(serveraddr));
	printf("connect 연결요청!!\n");

	//서버로 보낼 스트링 설정
	char buf[BUFSIZE + 1];
	sprintf(buf, "hello world!");

	//send()
	send(sock, buf, strlen(buf), 0);
	printf("메세지를 보냅니다.\n");

	//closesocket()
	closesocket(sock);

	//원속 종료
	WSACleanup();
	return 0;

}

 

간단하게 hello world를 클라이언트가 서버에게 보내는 코드였습니다. 

 

Ctrl+H 를 통해 기존 변수명과 변경을 원하는 변수명을 입력하여 모든 기존의 변수명을 빠르게 변경할 수 있다.

이번에는 싱글턴 패턴을 활용하여 안드로이드의 많은 기능을 활용하는 코드를 간단하게 보여드리겠습니다!

참고로 밑의 유튜브는 제가 참고한 영상입니다.

 

이번 시간에는 권한 설정 + 권한이 필요한 기능 사용입니다.

 

https://www.youtube.com/watch?v=B7a6xpMXDYE&t=502s

저는 이번에 유니티 툴에서 안드로이드 스튜디오의 메서드 getAllCellInfo()를 사용하고 싶었습니다.

그를 위한 코드를 보여드리겠습니다.

 

package com.example.nrlibrary;

import android.annotation.SuppressLint;
import android.content.Context;
import android.telephony.CellIdentityCdma;
import android.telephony.CellIdentityGsm;
import android.telephony.CellIdentityLte;
import android.telephony.CellIdentityWcdma;
import android.telephony.CellInfo;
import android.telephony.CellInfoCdma;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.telephony.TelephonyManager;
import android.widget.Toast;

import java.util.List;

public class cellnr {

    private static TelephonyManager telephonyManager;
    private static cellnr m_instance;
    private static Context context;

    // 싱글턴 메소드
    public static cellnr instance(Context ct) {
        if (m_instance == null) {
            context = ct;
            telephonyManager = (TelephonyManager) ct.getSystemService(ct.TELEPHONY_SERVICE);
            m_instance = new cellnr();
        }
        return m_instance;
    }

    private void ShowToast(String msg, int i) {
        // i는 짧게 아니면 길게 화면에 보여줄 것인지 체크한다.
        if (i == 0) // 짧은 경우
        {
            Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
        } else { // 길게 보이는 경우
            Toast.makeText(context, msg, Toast.LENGTH_LONG).show();

        }
    }
    
    @SuppressLint("MissingPermission")
    String easy_cell_info() {
        TelephonyManager tm = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);
        return tm.getAllCellInfo().toString();
    }

위 코드를 설명하겠습니다.

우선 TelephonyManager와 Class 그리고 Context를  static을 활용하여 선언하였고

instance 싱글턴 메서드를 통해서만 접근할 수 있게 하였습니다.

 

telephonyManager 같은 경우 위치 정보의 권한이 필요로 합니다. 

따라서 easy_cell_info 메소드를 보면 위에 MissingPermission이라고 되어 있습니다.

이것은 간단하게 권한 사용을 거부당했는지 체크하는 함수를 사용하지 않겠다는 의미입니다.

기본적으로는 권한 사용 거부 여부를 체크하는 조건문을 달아야 합니다.

하지만 여기서 체크하게 되면 뭔가 오류가 생겨서 그냥 무시하고 유니티에서 체크하도록 하였습니다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Android;
using UnityEngine.UI;

public class check_5G : MonoBehaviour
{
    private AndroidJavaObject UnityInstance;
    private AndroidJavaObject UnityActivity;
    public Text text;

    void Start()
    {
        AndroidJavaClass ajc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        UnityActivity = ajc.GetStatic<AndroidJavaObject>("currentActivity");

        AndroidJavaClass ajc2 = new AndroidJavaClass("com.example.nrlibrary.cellnr");
        UnityInstance = ajc2.CallStatic<AndroidJavaObject>("instance", UnityActivity);


        StartCoroutine(DelayEffect());
    }
    private IEnumerator DelayEffect()

    {

        while (true)

        {
            ShowCell5();

            /** 1초 딜레이 **/

            yield return new WaitForSeconds(1f);
        }

    }

    public void ShowCell5()
    {
        text.text = UnityInstance.Call<string>("easy_cell_info");

    }

 위 코드는 유니티 코드입니다.  start에서 하고 있는 작업은 간단하게 싱글턴 패턴 메서드 instance를 사용하기 위한

작업과 코 루틴 함수 getCellInfo() 통신 정보 획득 함수를 사용하고 있습니다.

ShowCell5에 있는 easay_cell_info를 사용하기 위해서는 미리 위치 정보를 확인할 수 있는 권한이 있어야 합니다.

 

유니티에서 권한 설정을 위해 AndroidManifest.xml 파일이 필요합니다. 파일의 위치는

저 같은 경우 아래와 같았습니다.

C:\Program Files\Unity\Hub\Editor\2019.2.17f1\Editor\Data\PlaybackEngines\AndroidPlayer\Apk

 

일반적인 경우로는

- Unity 설치 폴더/Editor/Data/PlaybackEngines/AndroidPlayer/Apk/AndroidManifest.xml

- 대상 경로 : {Project Root}/Assets/Plugins/Android/AndroidManifest.xml

에서  AndroidManifest.xml 파일이 있고  AndroidManifest.xml 파일을 가져와서

Plugins/Android폴더 안에 넣어서 사용할 수 있습니다.

저 같은 경우 위치 정보와 휴대폰 상태 정보가 필요하여 아래와 같이 퍼미션을 사용한다고 xml 파일에 명시하였습니다.

 

 

 

저는 위치 정보 권한을 시작하자마자 획득하기 위해서 아래의 코드를 사용하였습니다.

아래의 코드는 어느 블로거 님의 글을 통해 학습한 내용을 제가 필요한 코드로 바꿔 사용한 코드이며

설명은 블로거 님의 블로그를 통해 자세히 알아보실 수 있습니다.

https://mentum.tistory.com/150

 

유니티 퍼미션 체크 적용기. (Unity Permission Check) 2019.11.14 재작성.

2019.11.14 재작성. 유니티 안드로이드에서 스크린샷을 저장하기 위해 권한 부분을 다시 작성해야해서 하는 김에 이 글도 재작성 하였다. 2019/11/14 - [Unity/프로그래밍] - 유니티 안드로이드 스크린샷

mentum.tistory.com

 

using System;
using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Android;

// 매니페스트 선언필요.  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
public class PermissionCheck : MonoBehaviour
{
    [SerializeField] private GameObject panel; 
    bool onCheck = false;

    private void Start()
    {
        if (onCheck == false)
        {
            StartCoroutine("PermissionCheckCoroutine");
            panel.SetActive(true);
        }
    }

    public void PressBtnCapture()
    {
        if (onCheck == false)
        {
            StartCoroutine("PermissionCheckCoroutine");
            panel.SetActive(true);
        }
    }

    IEnumerator PermissionCheckCoroutine()
    {
        onCheck = true;

        yield return new WaitForEndOfFrame();
        if (Permission.HasUserAuthorizedPermission(Permission.FineLocation) == false)
        {
            Permission.RequestUserPermission(Permission.FineLocation);

            yield return new WaitForSeconds(0.2f); // 0.2초의 딜레이 후 focus를 체크하자.
            yield return new WaitUntil(() => Application.isFocused == true);

            if (Permission.HasUserAuthorizedPermission(Permission.FineLocation) == false)
            {
                // 다이얼로그를 위해 별도의 플러그인을 사용했기 때문에 주석처리. 그냥 별도의 UI를 만들어주면 됨.
                //AGAlertDialog.ShowMessageDialog("권한 필요", "스크린샷을 저장하기 위해 저장소 권한이 필요합니다.",
                //"Ok", () => OpenAppSetting(),
                //"No!", () => AGUIMisc.ShowToast("저장소 요청 거절됨"));

                OpenAppSetting(); // 원래는 다이얼로그 선택에서 Yes를 누르면 호출됨.
                onCheck = false;
                yield break;

            }
        }

        // 권한을 사용해서 처리하는 부분. 스크린샷이나, 파일 저장 등등.

        onCheck = false;
    }





    // 해당 앱의 설정창을 호출한다.
    // https://forum.unity.com/threads/redirect-to-app-settings.461140/
    private void OpenAppSetting()
    {
        try
        {
#if UNITY_ANDROID
            using (var unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
            using (AndroidJavaObject currentActivityObject = unityClass.GetStatic<AndroidJavaObject>("currentActivity"))
            {
                string packageName = currentActivityObject.Call<string>("getPackageName");

                using (var uriClass = new AndroidJavaClass("android.net.Uri"))
                using (AndroidJavaObject uriObject = uriClass.CallStatic<AndroidJavaObject>("fromParts", "package", packageName, null))
                using (var intentObject = new AndroidJavaObject("android.content.Intent", "android.settings.APPLICATION_DETAILS_SETTINGS", uriObject))
                {
                    intentObject.Call<AndroidJavaObject>("addCategory", "android.intent.category.DEFAULT");
                    intentObject.Call<AndroidJavaObject>("setFlags", 0x10000000);
                    currentActivityObject.Call("startActivity", intentObject);
                }
            }
#endif
        }
        catch (Exception ex)
        {
            Debug.LogException(ex);
        }
    }
}

안녕하세요 요즘 장마철이 끝나지 않고 비가 계속 쏟아지는데 답답하네요 ㅎㅎ 새로운 동내로 이사 와서 첫 주말 자전거 타고 둘러보려 했는데 아쉽네요 그런 관계로 안드로이드 플러그인 사용에 대해 알려드리겠습니다!

 

저는 처음 사용할 때는 삽질을 많이 했지만 여러분은 간단히 되길 바라면서 시작해보겠습니다.

 

 

우선 안드로이드 프로젝트를 만들어 주시기 바랍니다. 

empty Activity 로 하셔도 되고 

No Activity를 하셔도 무방합니다.

저는 일단 처음에는 안드로이드에서 만든 메서드를 사용해보고 잘 되는지 확인하기 위해서 Empty Activity로 시작해서 실제 구동되는지 확인하고 넘어갔었습니다.

 

 

 

다음 화면입니다.

여기서 주의하셔야 할 것은 Minimum SDK 입니다. 

그 이유는 유니티에서도 Minimum SDK를 설정하는데 안드로이드 Minimum과 유니티 Minimum이 일치하지 않으면 오류가 생기게 됩니다. 잘 기억해두셨다가 유니티에서도 같게끔 설정해주세요

 

유니티 프로젝트가 성공적으로 생성되고 gradle 파일들도 성공적으로 빌드되었다면 File -> New -> New Module로 들어가 모듈을 생성해줍니다. 타입은 Android Library로 선택해주세요

 

 

모듈이 생성되면 androidTest, test 파일을 지워주세요 저는 진행하다 까먹어서 후에 지웠습니다. 이 파일들이 같이 있으면 중복으로 오류가 생길 수도 있답니다.

 

 

생성된 모듈에 클래스를 생성해주세요. 저는 test_String으로 만들겠습니다.

 

아래의 이미지와 같이 문자열 반환 메소드를 만들었습니다. 우선 플러그인이 되는지 확인을 위해 간단한 문자열 반환 함수만 사용하겠습니다. 기본적으로 함수를 static을 붙여서 만든 이유는 static을 안 붙이고 유니티에서 호출하면 호출이 되질 않습니다. static을 안 붙이고 사용하려고 하신다면 싱글턴 패턴을 이용하셔야 합니다. 다음 글에서 다루겠습니다.

이제 Build -> Make Module '모듈명' 을 클릭해주세요

 

그다음으로, 생성한 모듈을 우클릭하여 Show in Explorer을 선택해서 폴더를 엽니다.

 

 

mylibrary를 클릭(본인의 모듈명)

 

outputs를 클릭

 

 

aar을 클릭

 

aar 파일이 만들어 진 것을 볼 수 있습니다. 

이 파일을 이용해서 유니티에서 안드로이드에서 구현된 메서드를 사용할 수 있도록 할 수 있습니다.

 

이제 유니티로 넘어가겠습니다.

 

유니티 프로젝트를 생성해주세요

생성되었다면, 위 탭 창에서 File -> Build Setting 을 클릭해주세요

플랫폼을 Android로 설정해주세요.

다음으로, Player Setting... 을 클릭해서 Other Setting에있는 Identification에서 Minimum API Level을 안드로이드 Minimum SDK 레벨과 동일하게 설정해주세요 중요합니다.

 

 

다음으로 위로 올리면 Company Name이 있습니다. DefaultCompany로 남겨두지 마시고 다른 아무 이름이나 원하는 이름으로 변경해주세요

 

 

다음으로 폴더를 생성하겠습니다. 

Assets -> Plugins -> Android 순으로 폴더를 제작해주세요.

 

그곳에 아까 만들어둔 aar 파일을 넣어주세요

이제 Assets 폴더에다 C# 스크립트를 제작하도록 하겠습니다. 코드는 일단 아래 이미지와 같이 만들어 주세요

 

코드를 보면 new AndroidJavaClass(""); 부분에 보면 빈 문자열을 넣고 있습니다.

안드로이드 프로젝트로 돌아가서 패키지 경로를 확인해주세요

 

 

저 같은 경우 com.example.mylibrary라고 돼있는 것을 확인할 수 있습니다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class NewBehaviourScript : MonoBehaviour
{
    private AndroidJavaObject UnityInstance;
    [SerializeField] private Text text;

    // Start is called before the first frame update
    void Start()
    {
        AndroidJavaClass ajc = new AndroidJavaClass("com.example.mylibrary.test_String");
        string str = ajc.CallStatic<string>("returnString");

       text.text = str;
    }

}

ajc.CallStatic은 스태틱 메서드를 호출할 때 사용합니다.

ajc.Call 은 일반 메소드를 호출할 때 사용합니다.

Call로 호출을 원한다면 static으로 선언된 싱글턴 메서드를 호출한 후 생성된 Instance를 통해 가능합니다.

아래와 같이 객체를 생성하여 주시기 바랍니다.

PluginManager는 엠티 오브젝트입니다.

 

 

플로그인 매니저에 방금 만든 스크립트를 넣어주고 Text에 Text를 드래그 앤 드롭해주세요 무슨 말인지 알죠?

 

UI text 사이즈를 위와 같이 키우고 폰트 사이즈를 50 정도로 맞춘 다음 글자를 가운데 맞춤을 해주세요

성공적이네요 ㅎㅎ 위 이미지는 모바일에서 구동된 이미지입니다. 그냥 유니티 환경에서 플레이 하면 문자열이 보이지 않게 되네요

일단 간단하게 유니티 플러그인을 실수 없이 만들 수 있도록 구현해보았습니다.

하지만 유니티에서 안드로이드를 사용하고 싶다는 것은 모바일 기능을 이용하고 싶다는 것일 것입니다.

그러면 유니티로 안드로이드 Context를 불러와서 사용해야 하거나 권한 설정을 해야 할 수 있습니다. 그 점에 대해서는 다음 글에서 다루겠습니다. 수고하셨습니다~

 

https://www.netmanias.com/ko/?m=view&id=techdocs&no=5138

 

LTE 네트워크 구조

LTE 분야 첫 문서로 LTE 네트워크 구조를 소개한다. 먼저 LTE 네트워크 참조 모델을 정의하고 LTE 네트워크를 구성하는 기본적인 Evolved Packet System(EPS) 엔터티들과 각 엔터티 기능을 기술한다. 이어서

www.netmanias.com

위 사이트에서 배운 내용을 정리한 글입니다.

 

 

LTE 네트워크는 무선 접속망(E-UTRAN) 관련 기술을 다루는 LTE 부분과 Core 망 관련 기술을 다루는 EPC 부분으로 나누어지고 LTE와 EPC를 통합하여 EPS라 일컫는다. 

LTE 네트워크는 E2E all-IP 네트워크 트래픽 흐름은 모두 IP 기반으로 동작한다.

 

사용자 평면(User Plane) : 데이터 평면이라고도 불리는 사용자 평면은 네트워크 사용자 트래픽을 전달한다.

 

제어 평면(control plane): 신호 트래픽을 전달하는 네트워크의 일부분이며 라우팅을 담당한다. 제어 패킷은 라우터에서 발생하거나 라우터로 지정된다. 제어면의 기능은 시스템 구성과 관리를 포함한다.

 

AS : Acess Stratum  액세스 계층

액세스 계층은 무선 네트워크와 사용자 장비 사이의 UMTS 및 LTE 무선 통신 프로토콜 스택의 기능 계층입니다. 액세스 계층의 정의는 UMTS와 LTE간에 매우 다르지만, 두 경우 모두 액세스 계층은 무선 연결을 통해 데이터를 전송하고 무선 리소스를 관리합니다.

startum : 계층, 지층, Layer 보다 이의 상위개념으로 사용되는 용어

 

BSS : Business Support System  

사업 관리 시스템은 통신 서비스 제공자가 고객들을 대상으로 사업 운영을 수행하기 위해 사용하는 요소들이다. 운용 지원 시스템과 더불어 다양한 단대단 통신 서비스를 지원하기 위해 사용된다. BSS와 OSS는 자신만의 데이터 및 서비스 책임이 있다. from 위키백과

 

CDR : Charging Data Record  청구 데이터 기록

CDR은 통신에서 청구 가능한 통신 이벤트에 대한 정보의 형식화된 모음이다. CDR은 사용자 청구에 사용된다.

 

DL : Downlink

위성에서 지상국 방향의 링크이다

 

DRB : Data Radio Bearer

베어러 (Bearer) - 전달/전송의 운반체, 가상 컨테이너 등을 의미

bearer : 열매 맺는 초목

 

E2E : End to End

 

ECM : EPS Connection Management

EPS Connection Management 상태는 UE와 EPC간의 신호 전달 연결을 설명합니다. ECM에는 두가지 상태, 즉 ECM-ID및 커넥터 연결됨이 있습니다.

 

EMM : EPS Mobility Management

EMM State는 이동성 관리 절차에서 비롯된다. 

EPS 이동 관리

Mobility : 유동성, 이동

 

 

EPC : Evolved Packet Core

EPC)는 3GPP LTE (Long Term Evolution)망에서의 코어 네트워크 구조를 지칭한다. EPC는 GPRS 코어 네트워크의 진화된 형태 from 위키백과

 

EPS : Evolved Packet System

 

ESM : EPS Session Management

EPS Session Management는 EPS 베어러 컨텍스트 처리를 위한 절차를 제공한다. 접근 계층에 의해 제공되는 베어러 제어와 함께, 그것은 사용자 평면 베어러의 제어를 제공한다.

 

E-UTRA : Evoloved Universal Terrestrial Radio Access 

E-UTRA는 이동통신망을 위한 3세대 파트너십 프로젝트 LTE 업그레이드 경로의 무선 인터페이스이다. 진화된 범용 지상 무선 접속 기술의 준말인데 이는 롱 텀 에볼루션의 3GPP 작업 항목이며 3GPP LTE 사양 초기 초안에서 E-UTRA로도 알려져 있다

Terrestrial : 지구의 

진화된 범용 지상파 무선 엑세스

이미지 출처: http://terms.tta.or.kr/dictionary/dictionaryView.do?word_seq=166868-9

 

TTA정보통신용어사전

한국정보통신기술협회(TTA)는 정보통신 기술 발전과 타 분야와의 기술 융합에 따라 무수히 생성되는 정보통신용어를 해설하고 표준화하여, 전문가뿐만 아니라 비전문가들도 올바르게 활용할 수

terms.tta.or.kr

E-UTRAN : Evolved Universal Terrestrial Radio Access Network

 

이미지 출처 : http://terms.tta.or.kr/dictionary/dictionaryView.do?word_seq=166867-11 

 

TTA정보통신용어사전

한국정보통신기술협회(TTA)는 정보통신 기술 발전과 타 분야와의 기술 융합에 따라 무수히 생성되는 정보통신용어를 해설하고 표준화하여, 전문가뿐만 아니라 비전문가들도 올바르게 활용할 수

terms.tta.or.kr

 

GTP : GPRS Tunneling Protocol -> GPRS 를 전달하는 IP 기반 통신 프로토콜 그룹

GPRS (General Packet Radio Service) 

Tunneling : 터널을 파고 나가는

 

GTP-C :  GTP Control

 

GTP-U : GTP User

 

HSS : Home Subscriber Server

사용자 프로파일을 갖는 중앙 DB로 MME에게 사용자 인증 정보와 사용자 프로파일을 제공한다.

 

HomeSubscriberServer(HSS)는 IPMultimediaSubsystem(IMS)내에서 사용된 주 가입자 데이터베이스이며 네트워크 내 다른 엔터티에 대한 가입자의 세부 정보를 제공합니다. IMS를 통해 사용자는 상태에 따라 다른 서비스에 대한 액세스를 허용하거나 거부할 수 있습니다.

 

IP : Internet Protocol

 

LTE : Long Term Evolution

HSDPA 보다 한층 진화된 휴대전화 고속 무선 데이터 패킷통신규격이다. HSDPA의 진화된 규격인 HSPA+와 함께 3.9세대 무선통신규격으로 불린다.

 

MAC : Medium Access Control

 

MME : Mobility Management Entity

- E-UTRAN 제어 평면 엔터티로, 사용자 인증과 사용자 프로파일 다운로드를 위하여 HSS와 통신하고, NAS 시그널링을 통해 UE에게 EPS 이동성 관리(EMM) 및 EPS Session 관리(ESM)기능을 제공한다.  

- LTE 망의 "두뇌" 역할을 하는 장비 그 역할은 UE를 인증(Authentication) ,  EPS 베어러를 관리 , 가입자의 Mobility 상태를 관리

 

 

NAS : Non Access Stratum

NAS는 UMTS 프로토콜 스택에서 UE와 코어 네트워크간의 시그널링, 트래픽 메시지를 주고 받기 위한 기능적인 계층이다. NAS 영역의 하부에는 Mobile Management영역이, 상부에는 Communication Management영역이 있다.

from 위키백과

 

NRM : Network Reference Model

각 형태의 통신망들이 네트워크 구조 각 구성요소별로 쉬운 참조 및 이해를 돕기위해, 해당 네트워크를 기능적으로 구분시킨 기능 블럭 다이어그램을 말함

http://www.ktword.co.kr/abbr_view.php?nav=2&m_temp1=3976&id=290

 

네트워크 참조모델 [정보통신기술용어해설]

 

www.ktword.co.kr

 

LTE 네트워크 참조 모델

이미지 출처 :  https://www.netmanias.com/ko/?m=view&id=techdocs&no=10634

 

LTE 네트워크 구조

 

www.netmanias.com

 

 

 

S-GW(Serving Gateway) : E-UTRAN과 EPC의 종단점이 된다. eNB 간 핸드오버 및 3GPP 시스템 간 핸드오버시 anchoring point가 된다. 

 

P-GW(Packet Data Network Gateway) : UE를 외부 PDN망과 연결해주며 패킷 filtering을 제공한다. UE에게 IP 주소를 할당하고 3GPP와 non-3GPP 간 핸드 오버시 mobility anchoring point로 동작한다. PCRF로부터 PCC 규칙을 수신하여 적용하며 (Policy Enforcement) UE 당 과금 기능을 제공한다. 주요 기능은 다음과 같다.

- IP 라우팅 및 fowarding

- Per-SDF / Per-User 기반 패킷 filtering 

- UE IP 주소 할당

- 3GPP와 non-3GPP 간 Mobility anchoring

- PCEF 기능

- Per-SDF/Per-User 과금

 

 

참조점 프로토콜 설명
LTE-Uu E-UTRA
(제어 평면, 사용자 평면)
UE와 eNB 간 무선 인터페이스로 제어 평면 및 사용자 평면을 정의한다.
X2 X2-AP (제어 평면)
GTP-U (사용자 평면)
두 eNB 간 인터페이스로 제어 평면 및 사용자 평면을 정의한다.
S1-U GTP-U eNB 와 S-GW 간 인터페이스로 사용자 평면을 정의한다. 베어러 당 GTP 터널링을 제공한다.
S1-MME S1-AP eNB와 MME 간 인터페이스로 제어 평면을 정의한다. 
S11 GTP-C MME와 S-GW 간 인터페이스로 제어 평면을 정의한다. 사용자 당 GTP 터널링을 제공한다.
S5 GTP-C(제어 평면)
GTP-U(사용자 평면)
S-GW와 P-GW간 인터페이스로 제어 평면 및 사용자 평면을 정의한다. 사용자 평면에서 베어러 당 GTP 터널링을 제공하고 제어 평면에서 사용자 당 GTP 터널 관리를 제공한다. 
S6a Diameter HSS와 MME 간 인터페이스로 제어 평면을 정의한다. UE 가입 정보 및 인증 정보를 교환한다.
Sp Diameter SPR과 PCRF 간 인터페이스로 제어 평면을 정의한다.
Gx Diameter PCRF와 P-GW간 인터페이스로 제어 평면을 정의한다. QoS 정책 및 과금 제어를 위한 인터페이스로 정책 제어 규칙 및 과금 규칙을 전달한다.
Gy Diameter OCS와 P-GW 간 인터페이스로 제어 평면을 정의한다. 
Gz GTP' OFCS와 P-GW간 인터페이스로 제어 평면을 정의한다.
SGi IP P-GW와 PDN 간 인터페이스로 사용자 평면과 제어 평면을 정의한다.
사용자 평면에서는 IETF 기반 IP 패킷 forwarding 프로토콜이 사용되고 제어 평면에서는 DHCP와 RADIUS/Diameter와 같은 프로토콜이 사용된다.

 

핸드오버 : 핸드오버는 단말기가 연결된 기지국의 서비스 공간에서 다른 기지국의 서비스 공간으로 이동할 때, 단말기가 다른 기지국의 서비스 공간에 할당한 통화 채널에 동조하여 서비스가 연결되는 기능을 일컫는다. from 위키백과 

 

OCS : Online Charging System

- 실시간 credit 제어를 제공하고 volume, time, event 기반 과금 기능을 제공한다. 

- 온라인 과금 시스템 은 통신 서비스 공급자가 고객의 실시간 서비스 사용기반 과금을 할 수 있도록 하는 시스템이다.

from 위키백과

 

OFCS : Offline Charging System

- CDR 기반 과금 정보를 제공한다.

- OFCS 는 오프라인 거래 시스템의 핵심 요소이다. OFCS 는 MSC, SGSN, CSCF등 잠재적으로 거래 관련 데이터를 제공하는 인터넷 노드들과 상호작용한다.

 

OSS : Operations Support System

운용 지원 시스템은 통신 서비스 제공자가 자사의 네트워크를 관리하기 위해 사용하는 컴퓨터 시스템이다. 네트워크 재고, 서비스 프로비저닝, 네트워크 구성, 장애 관리 등의 관리 기능을 지원한다. 사업 지원 시스템과 더불어 다양한 단대단 통신 서비스들을 지원하기 위해 사용된다. from 위키백과

 

PCC : Policy and Charging Control

정책 및 과금 제어

 

PCEF : Policy and Charging Enforcement Function

PCEF는 정책 및 청구 기능에서 수신한 결정을 시행하고 PCRF에 백 엑세스 및 및 가입자 정보를 중계하도록 설계 되었다.

 

PCRF : Policy and Charging Rule Function

정책 및 과금 제어 엔터티로 정책 제어 결정과 과금 제어 기능을 제공한다. PCRF에서 생성된 PCC 규칙은 P-GW로 전달된다.

 

정책 및 청구 규칙 기능은 멀티미디어 네트워크에서 정책 규칙을 결정하기 위해 실시간으로 지정된 소프트웨어 노드입니다. 정책 도구로서 PCRF는 차세대 네트워크에서 중심적인 역할을합니다. from 위키백과

 

PDCP : Packet Data Convergence Protocol

PDCP는 UMTS내 무선 트래픽 스택의 계층 중 하나이며, IP 헤더 압축 및 압축 해지, 사용자 데이터의 전송, Radio Bearer에 대한 시퀀스 번호 유지를 수행한다. 압축 기술은 RFC 2507 또는 RFC 3095에 기반한다.

Convergence : 수렴

 

PDN : Packet Data Network

공공 데이터 네트워크는 일반 대중을위한 데이터 전송 서비스를 제공하기 위해 통신 관리 부서 또는 공인 된 개인 운영 기관에서 설정하고 운영하는 네트워크입니다.

 

QoS : Quality of Service

QoS는 다른 응용 프로그램, 사용자, 데이터 흐름 등에 우선 순위를 정하여, 데이터 전송에 특정 수준의 성능을 보장하기 위한 능력을 말한다.

 

RLC : Radio Link Control

무선 링크 제어는 공중 인터페이스에서 UMTS 및 LTE에 사용되는 계층 2 무선 링크 프로토콜입니다. 이 프로토콜은 UMTS의 TS 25.322, LTE의 TS 36.322 및 5G New Radio의 TS 38.322에서 3GPP로 지정됩니다. from 위키백과

 

RRC : Radio Resource Control

무선 자원 제어 프로토콜은 무선 인터페이스의 UMTS 및 LTE에서 사용됩니다. UE와 eNB 사이에 존재하며 IP 레벨에 존재하는 계층입니다. 이 프로토콜은 UMTS의 경우 TS 25.331 및 LTE의 경우 TS 36.331에서 3GPP로 지정됩니다.

 

RRM : Radio Resource Management

무선 자원 제어 프로토콜은 무선 인터페이스의 UMTS 및 LTE에서 사용됩니다. UE와 eNB 사이에 존재하며 IP 레벨에 존재하는 계층입니다. 이 프로토콜은 UMTS의 경우 TS 25.331 및 LTE의 경우 TS 36.331에서 3GPP로 지정됩니다. 위키백과

 

S1AP : S1 Application Protocol

S1애플리케이션 프로토콜(S1AP)은 E-UTRAN과 진화된 패킷 코어(EPC)사이에서 제어부 신호 전달을 제공합니다.

 

SCTP : Stream Control Transmission Protocol

스트림 제어 전송 프로토콜은 컴퓨터 네트워킹에서 프로토콜 번호 132를 사용하는 전송 계층 프로토콜의 하나로서, 잘 알려진 프로토콜인 전송 제어 프로토콜, 사용자 데이터그램 프로토콜와 비슷한 역할을 수행한다. TCP와 UDP의 동일한 서비스 기능들 가운데 일부를 제공한다. 

 

SDF : Service Data Flow

통화와 관련된 음성 패킷의 흐름이나 웹 사이트에서의 스트리밍 데이터와 같은 가입자에게 제공되는 서비스를 나타내는 패킷의 흐름을 설명합니다.

 

SN : Sequence Number

시퀸스 넘버

 

SPR : Subscriber Profile Repository

- PCR에게 가입자 및 가입관련 정보를 제공한다. PCRF는 이를 수신하여 가입자 기반 정책을 수행하고 과금 규칙을 생성한다. 

- 3GPP 표준에 따라 정의된 가입자별 정책 제어 데이터를 저장 및 관리하는 시스템이다.

 

TEID : Tunnel Endpoint Identifier

TEID는 수신 GTP-U(GPRS터널링 프로토콜-사용자)또는 GTP-C(GPRS터널링 프로토콜-제어)프로토콜 실체에서 터널 끝점을 명확하게 식별합니다. GTP터널의 수신 측은 전송 측에서 사용할 TEID값을 로컬로 할당합니다. TEID값은 GTP-C메시지(또는 IMT-2000지상파 무선 액세스 네트워크의 RANAP)를 사용하여 터널 엔드 포인트 간에 교환된다.

 

UE : User Equipment

- LTE-Uu 무선 인터페이스를 통하여 eNB와 접속한다.

- User Equipment는 정보통신 용어의 하나로 5G 서비스가 제공되는 통신대상 단말의 수를 의미한다. UE Speed는 서비스가 제공되는 통신 대상 지역에 위치한 단말의 이동속도를 의미한다. from 위키백과

 

eNB Evolved Node B

사용자에게 무선 인터페이스를 제공한다. 무선 베어러 제어, 무선 수락 제어, 동적 무선 자원 할당, load balancing 및 셀 간 간섭제어(ICIC)와 같은 무선 자원 관리(RRM) 기능을 제공한다. 

evolved : 진화된

 

UDP : User Datagram Protocol

transport 계층의 통신 프로토콜로, 신뢰성이 낮은 프로토콜로써, 완전성을 보증하지 않으나, 가상회선을 굳이 확립할 필요가 없고, 유연하며 효율적 응용의 데이터 전송에 적합

 

X2-AP : X2 Application Protocol 

X2AP프로토콜은 E-UTRAN내의 UE이동성을 처리하는 데 사용

 

3GPP는 이동통신 관련 단체들 간의 공동 연구 프로젝트로 국제전기통신연합의 IMT-2000 프로젝트의 범위 내에서 - 전 세계적으로 적용 가능한 - 3세대 이동통신 시스템 규격의 작성을 목적으로 하고 있다.

 

Diameter

다이어미터 프로토콜은 컴퓨터 네트워크에서 사용되는 인증, 인가 및 과금 프로토콜이다. 다이어미터 프로토콜 보다 앞서 사용된 RADIUS 프로토콜에서 훨씬 더 유용하게 진화되었고 RADIUS 프로토콜을 대체하고 있다. from 위키백과

 

 

 

 

pwd: 본인이 머물고 있는 디렉토리 확인

 

cd: 디렉토리 변경 

- cd .. 상위 디렉터리로 이동

- cd / 루트 디렉터리로 이동

- cd ~ 로그인된 계정의 홈디렉토리로 이동

./ 는 현재 디렉토리를 의미한다.

 

ls(list) 

- ls -l 를 하면 디렉터리 내에있는 파일들의 권한등 자세한 사항을 관찰할 수 있다.

 

(도움말 보기)man

ex) man touch -> 터치의 기능에대해 볼 수 있다.

 

touch --help 

- touch의 기능에 대해 볼 수 있다.

 

 

mv: 파일 이동, 파일 이름 변경

ex) mv 원하는 파일 경로, mv 원하는 파일 변경될 이름

 

파일내용확인(cat, more, less)

 

cat (concatenate : 연쇄시키다.) : 파일 내용 확인

ex) cat newfile

 

more : 터미널에 보여줄 수 있는 만큼만 출력된다.

less : 문자열 검색 기능

 

ifconfig (window의 ipconfig와 유사) : 네트워크 정보 보기

 

find : 해당 경로에서 원하는 파일을 찾는 방법

ex) find -name 하위 디렉터리에 있는 파일 이름

- *를 사용하여 파일명으로 지정한 단어가 포함된 모든 파일 찾기가 가능하다.

 

환경 변수가 보관되는 디렉토리는 echo 명령어로 확인할 수 있다.

ex) echo $PATH

 

which : 환경 변수에서 바이너리 찾기

ex) which cp

 

whereis: 찾을 파일을 대상경로를 지정하지 않아도 모든 디렉터리에서 검색할 수 있다.

ex) whereis cp

 

파일 표시 : -rw-r--r-- 

디렉터리 표시 : drwxr-xr-x

 

소유자 / 그룹 / 그 외 사용자(other)

(r)읽기/(w)쓰기/(x)실행

 

 

 

 

 

 

 

 

 

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class move_arrow : MonoBehaviour
{

    public int arrow_pos { get; set; } = 1;
    private IEnumerator arrow_trans()
    {
        while (true)
        {
            switch (arrow_pos)
            {
                case 1:
                    transform.localPosition = new Vector3(-500, 200, -277);
                    break;
                case 2:
                    transform.localPosition = new Vector3(-290, 200, -277);
                    break;
                case 3:
                    transform.localPosition = new Vector3(-100, 200, -277);
                    break;
                case 4:
                    transform.localPosition = new Vector3(90, 200, -277);
                    break;
                case 5:
                    transform.localPosition = new Vector3(280, 200, -277);
                    break;
                case 6:
                    transform.localPosition = new Vector3(480, 200, -277);
                    break;
            }

            /** 1초 딜레이 **/
            yield return new WaitForSeconds(3f);
        }

    }

    private void OnEnable()
    {
        StartCoroutine(arrow_trans());
    }

}

<코드 설명>

transform.position 으로 하지 않고 transform.localPosition으로 한 이유는 객체가 어떤 부모 객체에 속하기 때문이다.

 

<실행 결과>

 

9_day.ipynb
0.01MB

 

 

 

성적을 입력받아 합격 여부를 알려주는 프로그램

In [16]:
graduation,score = map(float, input("졸업학점과 이수학점을 입력하시오. : ").split())

if graduation >=2.0 and score >=140:
    print("졸업가능")
elif graduation < 2.0 and score >=140 :
    print("졸업학점 부족")
elif score <140 and graduation >=2.0 :
    print("이수학점 부족")
else :
    print("둘다 부족")
 
졸업학점과 이수학점을 입력하시오. : 2.0 140
졸업가능
 

출생년도를 입력받아서 재난지원금 신청 가능 요일 알려주는 프로그램

In [21]:
str = input("출생년도를 입력하시오. : ")
if str[3] == '1' or str[3] == '6':
    print("월요일에 재난 지원금 신청 가능")
elif str[3] == '2' or str[3] == '7':
    print("화요일에 재난 지원금 신청 가능")
elif str[3] == '3' or str[3] == '8':
    print("수요일에 재난 지원금 신청 가능")
elif str[3] == '4' or str[3] == '9':
    print("목요일에 재난 지원금 신청 가능")
elif str[3] == '5' or str[3] == '0':
    print("금요일에 재난 지원금 신청 가능")
 
출생년도를 입력하시오. : 1990
0
금요일에 재난 지원금 신청 가능
 

문자열을 입력받아 홀수자리의 문자열이면 가운데 짝수면 가운데 근접 2문자를 출력하는 프로그램

In [34]:
str = input("문자열을 입력하세요")
len1 = len(str)%2
len2 = len(str)/2

if len1:
    print(str[round(len2)])
else :
    print(str[int(len2 -1)], str[int(len2)])
    
 
문자열을 입력하세요python
t h
 

외부 파일 리스트 정보를 통해 합계와 평균을 구하는 프로그램

In [49]:
import math

f = open('score.txt','r')
line = f.readline()
a= list(map(int,line.split(',')))
sum1, avg1 =math.ceil(sum(a)), round(sum(a)/len(a),2)
print("합계는", sum1, "평균은", avg1, "입니다.")
 
합계는 169 평균은 28.17 입니다.
 

컴퓨터와 가위바위보 하는 프로그램

In [69]:
import random
count =0

while True:
    rn = random.randint(1, 3)
    if rn==1:
        com = '가위'
    elif rn==2:
        com = '바위'
    elif rn==3:
        com = '보'
        
    player = input("가위, 바위, 보 중 하나를 입력하세요.")
    if player =='가위' or player =='보' or player=='바위' :
        if (com=='가위' and player== '보') or(com=='바위' and player== '가위') or(com=='보' and player== '바위') :
            print('com='+com+'  player='+player+' is com win')
                    
        elif (com=='보' and player== '가위') or(com=='가위' and player== '바위') or(com=='바위' and player== '보') :
            print('com='+com+'  player='+player+' is player win')
            count += 1
            if count >=3 :
                print("player가 3승으로 종료합니다.")
                break
        else :
            print('com='+com+'  player='+player+' is draw')                  
    else :
        print("잘못 입력했습니다.")
        continue
        
 
가위, 바위, 보 중 하나를 입력하세요.가위
com=바위  player=가위 is com win
가위, 바위, 보 중 하나를 입력하세요.바위
com=가위  player=바위 is player win
가위, 바위, 보 중 하나를 입력하세요.보
com=바위  player=보 is player win
가위, 바위, 보 중 하나를 입력하세요.보
com=보  player=보 is draw
가위, 바위, 보 중 하나를 입력하세요.보
com=가위  player=보 is com win
가위, 바위, 보 중 하나를 입력하세요.가위
com=가위  player=가위 is draw
가위, 바위, 보 중 하나를 입력하세요.보
com=바위  player=보 is player win
player가 3승으로 종료합니다.

3_day.ipynb
0.02MB

 

In [1]:
dic={1:'a'}
In [2]:
dic
Out[2]:
{1: 'a'}
In [3]:
dic[2] ='b'
dic
Out[3]:
{1: 'a', 2: 'b'}
In [4]:
dic[3] = [1,2,3]
dic
Out[4]:
{1: 'a', 2: 'b', 3: [1, 2, 3]}
In [6]:
dic["name"]="honggildong"
dic
Out[6]:
{1: 'a', 2: 'b', 3: [1, 2, 3], 'name': 'honggildong'}
In [7]:
del dic[2]
dic
Out[7]:
{1: 'a', 3: [1, 2, 3], 'name': 'honggildong'}
In [8]:
dic['name']
Out[8]:
'honggildong'
 

리스트는 키 값으로 사용할 수 없다.

In [9]:
dic[[1,2,4]] =[1,2,3,4]
 
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-87103fba05b6> in <module>
----> 1 dic[[1,2,4]] =[1,2,3,4]

TypeError: unhashable type: 'list'
In [10]:
dic.keys()
Out[10]:
dict_keys([1, 3, 'name'])
In [11]:
dic.values()
Out[11]:
dict_values(['a', [1, 2, 3], 'honggildong'])
In [12]:
dic.items()
Out[12]:
dict_items([(1, 'a'), (3, [1, 2, 3]), ('name', 'honggildong')])
In [13]:
dic.get('name')
Out[13]:
'honggildong'
In [14]:
dic[2]
 
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-14-f9d6f1c3d59c> in <module>
----> 1 dic[2]

KeyError: 2
 

get()함수를 사용하면 오류가 발생 하지 않는다. 되도록 get을 사용하자

In [16]:
dic.get(2)
In [17]:
print(dic.get(2))
 
None
 

키값 in 딕셔너리

In [18]:
3 in dic
Out[18]:
True
In [19]:
2 in dic
Out[19]:
False
In [21]:
s1=set([1,2,3])
s1
Out[21]:
{1, 2, 3}
In [22]:
s2 = set("hello")
s2
Out[22]:
{'e', 'h', 'l', 'o'}
In [23]:
s3=[s1]
s3
type(s3)
Out[23]:
list
 

집합 정의

In [25]:
s1 = set([1, 2, 3, 4, 5, 6])
s2 = set([4, 5, 6, 7, 8, 9])
 

차집합

In [29]:
print(s1-s2)
print(s1.difference(s2))
print(s2-s1)
print(s2.difference(s1))
 
{1, 2, 3}
{1, 2, 3}
{8, 9, 7}
{8, 9, 7}
 

합집합

In [31]:
print(s1 | s2)
print(s1.union(s2))
 
{1, 2, 3, 4, 5, 6, 7, 8, 9}
{1, 2, 3, 4, 5, 6, 7, 8, 9}
 

교집합

In [28]:
print(s1 & s2)
print(s1.intersection(s2))
 
{4, 5, 6}
{4, 5, 6}
 

값 1개 추가하기(add)

In [32]:
s1 = set([1, 2, 3])
s1.add(4)
s1
Out[32]:
{1, 2, 3, 4}
 

값 여러 개 추가하기(update) tip) 리스트로 추가해야한다.

In [33]:
s1 = set([1, 2, 3])
s1.update([4, 5, 6])
s1
Out[33]:
{1, 2, 3, 4, 5, 6}
In [34]:
a=True
b=False
In [35]:
type(a)
Out[35]:
bool
In [36]:
c=5
d=7
c>d
Out[36]:
False
In [37]:
c == d
Out[37]:
False
In [38]:
c != d
Out[38]:
True
In [39]:
bool(2)
Out[39]:
True
In [40]:
bool(-1)
Out[40]:
True
In [41]:
bool("kyungnam")
Out[41]:
True
In [42]:
bool(" ")
Out[42]:
True
In [43]:
bool("")
Out[43]:
False
In [44]:
1 and 0
Out[44]:
0
In [45]:
1 or 0
Out[45]:
1
In [46]:
not False
Out[46]:
True
In [48]:
a=[1,2,3,4]
while a:
    print(a.pop())
 
4
3
2
1
In [ ]:
str1="kyungnam"
In [49]:
apple=10
Apple=20
In [50]:
print(apple)
print(Apple)
 
10
20
In [51]:
print(APple)
 
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-51-08860365de26> in <module>
----> 1 print(APple)

NameError: name 'APple' is not defined
 

파이썬에서는 변수명이 다르더라도 값이 같으면 같은 위치에 저장된다.

In [52]:
a=3
b=3
print(id(a))
print(id(b))
 
140707594805712
140707594805712
In [53]:
x=input()
 
10
In [54]:
print(x)
 
10
In [56]:
print('1', '2', '3', sep=":")
print('1', '2', '3', end=":")
 
1:2:3
1 2 3:
In [58]:
#한줄 주석
'''
여러줄
주석
'''
print("hello")
 
hello
 

3주차 문제

In [65]:
#1번
mid_term={'kor':90, 'eng':100, 'math':80}
del mid_term['eng']
mid_term['math'] = 80
mid_term['computer'] = 100;
print(mid_term)
 
{'kor': 90, 'math': 80, 'computer': 100}
In [94]:
#2번
final_term={'kor':90, 'eng':100, 'math':80}
total = sum(final_term.values())
term_avg = total/len(final_term)
print('총점 :', total)
print('평균 : ', term_avg)
 
총점 : 270
평균 :  90.0

+ Recent posts