12.7. 채널 콜백¶
protocol.register() 에 전달되는 백엔드 객체는 Python 클래스입니다. 프로토콜 라이브러리는 그 클래스에게 어떤 메서드를 구현했는지 묻지 않습니다. 대신 인스턴스를 살펴보고 발견한 메서드를 연결합니다. 이러한 인트로스펙션 덕분에 백엔드 인터페이스가 유연해집니다. 가장 작은 유용한 백엔드는 메서드 두 개이고, 가장 정교한 것은 열두 개이며, 애플리케이션은 메서드를 하나씩 추가하면서 각 기능을 선택적으로 활성화합니다.
12.7.1. 인트로스펙션 규칙¶
protocol.register() 가 실행되면, 라이브러리는 정해진 호출 가능 이름 목록을 훑으면서 백엔드 인스턴스에서 발견한 각각을 바인딩합니다:
클래스에
read를 추가하면CHANNEL_FLAG_READ이 켜집니다. 호스트가channel_read()를 호출하더라도 이 플래그가 설정되어 있어야만 백엔드에 도달합니다.write를 추가하면CHANNEL_FLAG_WRITE이 켜져channel_write()가 활성화됩니다.lock과unlock을 추가하면CHANNEL_FLAG_LOCK이 켜져, 호스트가 여러 패킷에 걸친 원자적 읽기를 위해 채널을 잠글 수 있게 됩니다.poll을 추가하면 호스트가 전체 읽기를 강제하지 않고도 “준비된 것이 있는가?”를 저렴하게 물어볼 수 있습니다.
메서드가 없는 것은 오류가 아닙니다. 프로토콜 라이브러리는 해당 기능을 비활성화된 채로 둘 뿐입니다. size 와 read 만 있는 백엔드도 완벽하게 유효하며, 이는 읽기 전용 데이터 채널입니다.
12.7.2. 읽기 전용 센서 채널¶
호스트가 요청할 때마다 새로운 측정값을 게시하고 호스트의 쓰기를 거부하는 센서 채널은 콜백 네 개를 활용합니다:
import protocol
import struct
class TempChannel:
def __init__(self, read_sensor):
self._read_sensor = read_sensor
self._buf = b''
self._fresh = False
def poll(self):
# Tell the host whether a reading is waiting.
return self._fresh
def size(self):
# Sample fresh data on every host-side size query.
value = self._read_sensor()
self._buf = struct.pack('<f', value)
self._fresh = True
return len(self._buf)
def read(self, offset, size):
end = offset + size
if end >= len(self._buf):
self._fresh = False
return self._buf[offset:end]
protocol.register(name='temp', backend=TempChannel(read_temperature))
각 메서드가 하는 일을 차례로 살펴보면:
poll은 신선도 플래그를 반환합니다. 호스트는 읽기 전에 이것을 호출하고,False가 반환되면 읽기를 완전히 건너뜁니다. 이는 “아직 새 데이터가 없음”에 대한 왕복 비용을 절약합니다.size는 요청 시 버퍼를 다시 생성하고 그 길이를 보고합니다. 여기서 샘플링을 수행하므로 백엔드는 백그라운드 작업이 필요 없습니다. 호스트 호출이 모든 측정을 구동합니다.read는 버퍼의 일부를 반환합니다. 버퍼가 협상된 최대 페이로드보다 클 때 프로토콜 라이브러리는 이것을 두 번 이상 호출할 수 있습니다.offset인수가 조각들을 차례로 훑습니다.write가 없으면 호스트의 쓰기는 백엔드가 관여하기 전에 프레이밍 계층에서 거부됩니다.
12.7.3. 전체 콜백 집합¶
참고로, 라이브러리가 백엔드에서 찾는 모든 메서드는 다음과 같습니다:
메서드 |
반환값 |
용도 |
|---|---|---|
|
object |
채널이 호스트에 처음 바인딩될 때의 선택적 일회성 초기화. 성공 시 |
|
bool |
데이터가 사용 가능할 때 |
|
bool |
원자적 다중 패킷 전송을 위해 채널을 확보합니다. |
|
bool |
이전의 |
|
int |
현재 채널에서 읽을 수 있는 바이트 수. |
|
tuple |
데이터 구조를 설명하는 최대 네 개의 정수(예: 이미지 높이, 너비, 바이트 수). 호스트가 형식이 지정된 버퍼를 언패킹하는 데 사용됩니다. |
|
bytes |
offset 에서 시작하여 최대 size 바이트를 반환합니다. 페이로드가 협상된 최대치를 초과할 때 조각마다 한 번씩 호출됩니다. |
|
bytes |
|
|
int |
호스트가 offset 에 data 를 썼습니다. |
|
int |
읽기/쓰기 모델을 벗어난 애플리케이션 정의 오피코드. 음수 반환은 오류입니다. |
|
object |
버퍼링된 데이터를 모두 버립니다. 호스트가 채널을 재설정하려 할 때 호출됩니다. |
|
bool |
물리적 전송 수단을 나타내는 백엔드(내장 USB 채널)에서만 의미가 있습니다. 애플리케이션 채널은 이것이 필요 없습니다. |
이것이 백엔드 인터페이스의 전부입니다. 열두 개의 메서드 이름은 모두 선택 사항이며, 프로토콜 라이브러리는 어떤 것이 존재하는지에 따라 각 채널이 무엇을 할 수 있는지 결정합니다.