asyncio 사용
- asyncio(Asynchronous I/O)는 비동기 프로그래밍을 위한 모듈이며 CPU 작업과 I/O를 병렬로 처리하게 해줌
- 동기(synchronous) 처리는 특정 작업이 끝나면 다음 작업을 처리하는 순차처리 방식이고,
비동기(asynchronous) 처리는 여러 작업을 처리하도록 예약한 뒤 작업이 끝나면 결과를 받는 방식
Coroutine
- 실행의 지연과 재개를 허용함으로서, non-preemptive(비 선점적) 멀티태스킹을 위한 subroutine을 일반화
- subroutine: 함수의 동작이 끝나면 자신을 호출하였던 main-routine으로 돌아오는 routine. 하나의 진입점과 하나의 탈출점.
- co-routine: routine을 진행하는 중간 멈춰서 특정 위치로 돌아갔다가 원래 위치로 돌아올 수 있는 routine (main-routine에 종속적이지 않음
다양한 진입점과 다양한 탈출점.
- 비 선점형 멀티태스킹: 병렬이 아닌 병행성(Concurrency)
→ 동시에 실행되는 것 처럼 보임. CPU 사용권을 뺏을 수 없음
→ 작업 교환 때 비용이 적음.
- 싱글 스레드에서 동작하는 비동기 동시성(Concurrency) 작업
- 멀티스레드를 대체하기 위한 것이 아닌, 스레드에서 대기시간을 최소화하는 것
- CPU와 리소스 낭비 방지 가능
Generator 기반 Co-routine
- yield 을 통해서 메인루틴과 서브 루틴간에 값을 이동하며 실행의 지연 및 재개.
def coroutine():
total = 0
while True:
num = yield total # total 발생 및 num에 값 저장
total += num
cr = coroutine()
print(next(cr)) # 처음 yield 까지 실행
print(cr.send(3)) # num에 3 저장 후 다음 yield 까지 실행
print(cr.send(2)) # num에 2 저장 후 다음 yield 까지 실행
"""
0
3
5
"""
native Co-routine
- asyncio 사용하여 구성된 코루틴
- 파이썬에서 제공하는 동시성 프로그래밍
- async/await 구문 사용
- async def 로 코루틴 함수 생성
- await로 awaitable 객체(코루틴 객체, 퓨처 객체, 테스트 객체) 실행 (native 코루틴 안에서만 사용 가능)
- asyncio.run(), asyncio.sleep(), asyncio.wait(), asyncio.gather(), asyncio.Queue() 등 사용
import time
import asyncio
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
def sync_say_after(delay, what):
time.sleep(delay)
print(what)
async def main():
s = time.time()
sync_say_after(3, "A")
sync_say_after(2, "B")
print(time.time() - s)
s = time.time()
await say_after(3, "A")
await say_after(2, "B")
print(time.time() - s)
s = time.time()
await asyncio.gather(
say_after(3, "A"),
say_after(2, "B")
)
print(time.time() - s)
asyncio.run(main())
"""
A
B
5.0051562786102295
A
B
5.026145935058594
B
A
3.00801157951355
"""
await 을 통한 awaitable 객체가 완료 될 때까지 대기
따라서 동기적으로 진행되는 첫 예시와, 비동기지만 await으로 대기하는 두번째 예시는 비슷한 시간 (3초 + 2초)이 소모
세번째 예시의 경우 두 코루틴 함수 동시 실행 후 늦게 종료되는 say_after(3, "A") 코드를 기다림.
따라서 3초 정도의 시간만 소모함.
python2 와 비교하여 python3의 가장 돋보이는 killer feature 는 비동기 프로그래밍 지원이라고 할 수 있음.
이를 위하여 python 3.4에 asyncio 모듈이 추가되었고, python 3.5에는 native coroutine 지원을 위한 async, await 키워드가 추가되었음
이들 기능을 이용하면 javascript나 다른 언어에서 지원하는 비동기 프로그래밍의 장점을 python에서도 사용할 수 있음
즉, 이벤트 방식이지만 blocking 방식의 프로그래밍처럼 sequential 하게 코드를 작성할 수 있어, 단일 thread로 수만개의
네트워크 연결을 처리하는 서버를 오류 가능성을 최소화하면서, 보다 편하게 개발할 수 있음.
https://blog.naver.com/chandong83/222309559122
import asyncio # 비동기화 모듈
from bleak import BleakScanner # BLE 검색 모듈
# 비동기 형태로 BLE 장치 검색
async def run():
# 검색 시작 (검색이 종료될때까지 대기)
# 기본 검색 시간은 5초
devices = await BleakScanner.discover()
# 검색된 장치들 리스트 출력
for d in devices:
print(d)
# 비동기 이벤트 루프 생성
loop = asyncio.get_event_loop()
# 비동기 형태로 run(검색) 함수 실행
# 완료될떄까지 대기
loop.run_until_complete(run())
"""
38:CC:22:36:12:55: None
4D:4B:C4:C6:A5:CC: None
43:AC:09:61:AE:61: None
86:2A:FD:62:E7:15: None
"""
import asyncio
from bleak import BleakScanner
async def run():
# 검색 시작(with 사용)
async with BleakScanner() as scanner:
# 5초간 대기
await asyncio.sleep(5.0)
# 검색된 장치 얻어오기
devices = await scanner.get_discovered_devices()
# 리스트 출력
for d in devices:
print(d)
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
"""
38:CC:22:36:12:55: None
86:2A:FD:62:E7:15: None
FA:B4:6A:30:FF:9A: None
"""
import asyncio
from bleak import BleakScanner
"""
장치가 검색되면 호출되는 콜백 함수
device : 장치 정보(bleak.backends.device.BLEDevice)
advertisement_data: 장치에서 송출하는 데이터
"""
def detection_callback(device, advertisement_data):
# 장치 주소와 신호세기, 그리고 advertiseent data 출력
print(device.address, "RSSI: ", device.rssi, "device detail: ", device.details, advertisement_data)
async def run():
# 검색 클래스 생성
scanner = BleakScanner()
# 콜백 함수 등록
scanner.register_detection_callback(detection_callback)
# 검색 시작
await scanner.start()
# 5초간 대기 이때 검색된 장치들이 있다면 등록된 콜백함수가 호출됨
await asyncio.sleep(5.0)
# 검색 중지
await scanner.stop()
# 지금까지 찾은 장치들 가져오기
devices = await scanner.get_discovered_devices()
# 지금까지 찾은 장치 리스트 출력
for d in devices:
print(d)
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
"""
FutureWarning: This method will be removed in a future version of Bleak. Use the detection_callback of the BleakScanner constructor instead.
scanner.register_detection_callback(detection_callback)
38:CC:22:36:12:55 RSSI: -83 AdvertisementData(manufacturer_data={19456: b'\x02\x15&\x86\xf3\x9c\xba\xdaFX\x85J\xa6.~^\x8b\x8d\x00\x01\x00\x00\xc9'}, rssi=-83)
38:CC:22:36:12:55 RSSI: -83 AdvertisementData(manufacturer_data={19456: b'\x02\x15&\x86\xf3\x9c\xba\xdaFX\x85J\xa6.~^\x8b\x8d\x00\x01\x00\x00\xc9'}, rssi=-83)
38:CC:22:36:12:55 RSSI: -83 AdvertisementData(manufacturer_data={19456: b'\x02\x15&\x86\xf3\x9c\xba\xdaFX\x85J\xa6.~^\x8b\x8d\x00\x01\x00\x00\xc9'}, rssi=-86)
14:C8:4A:4B:A4:20 RSSI: -85 AdvertisementData(manufacturer_data={6: b'\x01\t \x02\xed\x06/8z\xe5>s\x19\x89\xe7c6\xa3.\xdf\xf72E\x8c\x9f\x9c\x81'}, rssi=-85)
c:/Users/rogue/OneDrive/바탕 화면/New folder/ser.py:28: FutureWarning: This method will be removed in a future version of Bleak. Use the `discovered_devices` property instead.
devices = await scanner.get_discovered_devices()
38:CC:22:36:12:55: None
14:C8:4A:4B:A4:20: None
"""
"""
device 검색 콜백에 paramete인 device(bleak.backends.deivce.BLEDevice)의 변수 구조
address: BLE MAC 주소(mac address)
details: 장치 연결에 필요한 OS 세부 정보
metadata: UUID를 포함해 장치에서 송출하는 데이터(advertisement data)
name: BLE 장치명
rssi: 장치 신호 세기
"""
- Bluetooth 에서 전파의 세기 즉 신호세기를 RSSI라고 부름
RSSI는 Received Signal Strength Indicator의 약자로 수신기에서 수신되는 전파의 세기가 얼마인지를 수치로 나타내는 것
RSSI 값은 수신기에 들어오는 신호 수치가 얼마나 되는지를 의미하기 때문에 안테나의 이득 값이나 회로에 의한 손실은 고려하지 않은 값
이 용어는 Bluetooth 시스템에서만 쓰이는 단어가 아닌 RF 신호를 사용하는 모든 시스템에서 사용되고 있는데
그 중 하나가 LTE 모뎀과 같은 통신 모듈에서도 RSSI라는 단어를 사용함.
RSSI 값은 기본적으로 음수로 표현되며 0에 가까울수록 신호의 세기가 강함
신호의 범위는 대부분 0 ~ -100 까지 사용되며 RSSI가 -100 이라면 데이터 송수신 자체가 불안정함
RSSI 는 어느 정도 거리에 따라서 편차가 있을 수 있지만 RSSI 값 자체만으로 원하는 거리의 근사치를 구할 수 없음.
import asyncio
from bleak import BleakClient
address = "98:DA:60:03:B8:F8"
def on_disconnect(client):
print("Client with address {} got disconnected!".format(client.address))
async def run(address):
client = BleakClient(address)
try:
client.set_disconnected_callback(on_disconnect)
await client.connect()
print('connected')
except Exception as e:
print('error: ', e, end='')
finally:
print('start disconnect')
await client.disconnect()
loop = asyncio.get_event_loop()
loop.run_until_complete(run(address))
print('done')
import asyncio
from bleak import BleakClient
address = "98:DA:60:03:B8:F8"
async def run(address):
async with BleakClient(address) as client:
print('connected')
services = await client.get_services()
for service in services:
print(service)
print('\tuuid:', service.uuid)
print('\tcharacteristic list:')
for characteristic in service.characteristics:
print('\t\t', characteristic)
print('\t\tuuid:', characteristic.uuid)
print('\t\tdescription:', characteristic.description)
print('\t\tproperties:', characteristic.properties)
print('disconnect')
loop = asyncio.get_event_loop()
loop.run_until_complete(run(address))
print('done')
"""
services = await client.get_services()
00001800-0000-1000-8000-00805f9b34fb (Handle: 1): Generic Access Profile
uuid: 00001800-0000-1000-8000-00805f9b34fb
characteristic list:
00002a00-0000-1000-8000-00805f9b34fb (Handle: 2): Device Name
uuid: 00002a00-0000-1000-8000-00805f9b34fb
description: Device Name
properties: ['read']
00002a01-0000-1000-8000-00805f9b34fb (Handle: 4): Appearance
uuid: 00002a01-0000-1000-8000-00805f9b34fb
description: Appearance
properties: ['read']
00002a02-0000-1000-8000-00805f9b34fb (Handle: 6): Peripheral Privacy Flag
uuid: 00002a02-0000-1000-8000-00805f9b34fb
description: Peripheral Privacy Flag
properties: ['read']
00002a04-0000-1000-8000-00805f9b34fb (Handle: 8): Peripheral Preferred Connection Parameters
uuid: 00002a04-0000-1000-8000-00805f9b34fb
description: Peripheral Preferred Connection Parameters
properties: ['read']
00001801-0000-1000-8000-00805f9b34fb (Handle: 10): Generic Attribute Profile
uuid: 00001801-0000-1000-8000-00805f9b34fb
characteristic list:
00002a05-0000-1000-8000-00805f9b34fb (Handle: 11): Service Changed
uuid: 00002a05-0000-1000-8000-00805f9b34fb
description: Service Changed
properties: ['indicate']
0000180a-0000-1000-8000-00805f9b34fb (Handle: 14): Device Information
uuid: 0000180a-0000-1000-8000-00805f9b34fb
characteristic list:
00002a29-0000-1000-8000-00805f9b34fb (Handle: 15): Manufacturer Name String
uuid: 00002a29-0000-1000-8000-00805f9b34fb
description: Manufacturer Name String
properties: ['read']
00002a24-0000-1000-8000-00805f9b34fb (Handle: 17): Model Number String
uuid: 00002a24-0000-1000-8000-00805f9b34fb
description: Model Number String
properties: ['read']
00002a25-0000-1000-8000-00805f9b34fb (Handle: 19): Serial Number String
uuid: 00002a25-0000-1000-8000-00805f9b34fb
description: Serial Number String
properties: ['read']
00002a26-0000-1000-8000-00805f9b34fb (Handle: 21): Firmware Revision String
uuid: 00002a26-0000-1000-8000-00805f9b34fb
description: Firmware Revision String
properties: ['read']
00002a27-0000-1000-8000-00805f9b34fb (Handle: 23): Hardware Revision String
uuid: 00002a27-0000-1000-8000-00805f9b34fb
description: Hardware Revision String
properties: ['read']
00002a28-0000-1000-8000-00805f9b34fb (Handle: 25): Software Revision String
uuid: 00002a28-0000-1000-8000-00805f9b34fb
description: Software Revision String
properties: ['read']
00002a23-0000-1000-8000-00805f9b34fb (Handle: 27): System ID
uuid: 00002a23-0000-1000-8000-00805f9b34fb
description: System ID
properties: ['read']
00002a2a-0000-1000-8000-00805f9b34fb (Handle: 29): IEEE 11073-20601 Regulatory Cert. Data List
uuid: 00002a2a-0000-1000-8000-00805f9b34fb
description: IEEE 11073-20601 Regulatory Cert. Data List
properties: ['read']
00002a50-0000-1000-8000-00805f9b34fb (Handle: 31): PnP ID
uuid: 00002a50-0000-1000-8000-00805f9b34fb
description: PnP ID
properties: ['read']
0000ffe0-0000-1000-8000-00805f9b34fb (Handle: 33): Vendor specific
uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
characteristic list:
0000ffe1-0000-1000-8000-00805f9b34fb (Handle: 34): Vendor specific
uuid: 0000ffe1-0000-1000-8000-00805f9b34fb
description: Vendor specific
properties: ['notify']
0000ffe2-0000-1000-8000-00805f9b34fb (Handle: 37): Vendor specific
uuid: 0000ffe2-0000-1000-8000-00805f9b34fb
description: Vendor specific
properties: ['write-without-response', 'write']
disconnect
done
# #############################
Bluetooth 장치에는 0000ffe0-0000-1000-8000-00805f9b34fb 라는 서비스가 있고
여기에는 0000ffe1-0000-1000-8000-00805f9b34fb 라는 characteristic이 있음
0000ffe2-0000-1000-8000-00805f9b34fb 이거 사용하면될듯?
"""
- UUID란
네트워크 상에서 고유성이 보장되는 id를 만들기 위한 표준 규약
UUID는 Universally Unique Identifier의 약어이고 범용 고유 식별자라고 함
주로 분산 컴퓨팅 환경에서 사용되는 식별자임.
중앙관리시스템이 있는 환경이라면 각 세션에 일련번호를 부여해줌으로서 유일함을 보장할 수 있겠지만
중앙에서 관리되지 않는 분산환경이라면 개별 시스템이 id를 발급하더라도 유일성이 보장되어야 할 것이다.
이를 위해 탄생한 것이 범용고유식별자 UUID 이다. RFC 4122에 명시되어 있음
UUID는 128비트의 숫자이며, 32자리의 16진수로 표현됨.
네트워크 상에서 서로 모르는 개체들을 식별하고 구별하기 위해서는 각각의 고유한 이름이 필요
이 이름은 고유성(유일성)이 매우 중요함. 같은 이름을 갖는 개체가 존재한다면 구별이 불가능해지기 때문
고유성을 완벽하게 보장하려면 중앙관리시스템이 있어서 일련번호를 부여해주면 간단하지만 동시다발적이고
독립적으로 개발되고 있는 시스템들의 경우 중앙관리시스템은 불가능함
개발 주체가 스스로 이름을 짓도록 하되 고유성을 충족할 수 있는 방법이 필요함
이를 위하여 탄생한 것이 범용고유식별자(UUID)이며 국제기구에서 표준으로 정하고 있음
UUID표준에 따라 이름을 부여하면 고유성을 완벽하게 보장할 수는 없지만 실제 사용상에서 중복될 가능성이
거의 없다고 인정되기 때문에 많이 사용되고 있음.
'Network' 카테고리의 다른 글
Subnet (0) | 2023.04.19 |
---|---|
애드혹 네트워크(Ad hoc network) (0) | 2023.04.14 |
TCP/IP Layer (0) | 2022.12.17 |
Network Structure (0) | 2022.12.17 |
File Transfer Protocol (FTP) (0) | 2022.12.04 |