Pythonのsocketとは?

socketはネットワーク通信に利用するファイルの一種。
そして、このソケットに紐づけられた「ファイルディスクリプタ」を用いることで、アプリケーションに対してデータを送ることができる。
ファイルディスクリプタとは、プログラムが利用する標準入出力やファイル入出力をOSが識別するための識別子です。

### サーバサイド
1. socket()作成
2. bindはsocketをローカルのアドレスにバインド
3. listen()は接続を待ち受け
4. accept()は外部からの接続に対して新しいソケットをサック製
5. send()/receive()でデータの送受信
6. close()でソケットクローズ

### クライアントサイド
1. socket()でソケット作成
2. connect()はリモートソケットに接続
3. send()/receive()でデータの送受信
5. close()でソケットクローズ、ファイルディスクリプタ削除

### ソケット通信のバリエーション/パラメータ
ソケット通信の方式を決めるためのパラメータは、主に(1)アドレスファミリー、(2)ソケットタイプ

(1)アドレスファミリー
ソケットにバインドするアドレスの種類
・AF_UNIX: ローカル通信に使用する。同一マシン間でプロセス間通信を可能とする。
・AF_INET: IPv4インターネットプロトコル, TCP
・AF_INET6: IPv6インターネットプロトコル, TCP

(2)socket Type
TCPであればSOCK_STREAM, UDPであればSOCK_DGRAM
・SOCK_STREAM: 双方向のバイトストリーム
・SOCK_DGRAM: データグラム、UDPソケットで利用

import os
import socket

class BlockingServerBase:
    def __init__(self, timeout:int=60, buffer:int=1024):
        self.__socket = None
        self.__timeout = timeout
        self.__buffer = buffer
        self.close()

    def __del__(self):
        self.close()

    def close(self) -> None:
        try:
            self.__socket.shutdown(socket.SHUT_RDWR)
            self.__socket.close()
        except:
            pass
    
    def accept(self, address, family:int, type:int, proto:int) -> None:
        self.__socket = socket.socket(family, typ, proto)
        self.__socket.settimeout(self.__timeout)
        self.__socket.bind(address)
        self.__socket.listen(1)
        print("Server started:", address)
        conn, _ = self.__socket.accept()

        while True:
            try:
                message_recv = conn.recv(self.__buffer).decode('utf-8')
                message_resp = self.respond(message_recv)
                conn.send(message_resp.encode('utf-8'))
            except ConnectionResetError:
                break
            except BrokenPipeError:
                break
        self.close()

    def respond(self.message:str) -> str:
        return ""
import socket

class BaseClient:
    def __init__(self, timeout:int=10, buffer:int=1024)
        self.__socket = None
        self.__address = None
        self.__timeout = timeout
        self.__buffer = buffer

    def connect(self, address, family:int, typ:int, proto:int):
        self.__address = address
        self.__socket = socket.socket(family, typ, proto)
        self.__socket.settimeout(self.__timeout)
        self.__socket.connect(self.__address)

    def send(self, message:str="") -> None:
        flag = False
        while True:
            if message == "":
                message_send = input("> ")
            else:
                message_send=messsage
                flag = True
            self.__socket.send(message_send.encode('utf-8'))
            message_recv = self.__socket.recv(self.__buffer).decode('utf-8')
            self.received(message_recv)
            if flag:
                break

        try:
            self.__socket.shutdown(socket.SHUT_RDWR)
            self.__socket.close()
        except:
            pass

    def received(self, message:str):
        print(message)    

Pythonの[-4:]と[:-4]

BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
print(BASE58_ALPHABET[-4:])
print(BASE58_ALPHABET[:-4])

$ python3 test.py
wxyz
123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuv

テストコードを実行してみれば、そのまんまだけど、一見[-4:]と[:-4]がプログラム上で並ぶと困惑しますね。

Python enumerate()の使い方

enumerate()関数を利用することで、for文内のループ処理にインデックス番号を付与できる

ary = ['ドル', 'ユーロ', 'ポンド', 'リラ']
for i, d in enumerate(ary):
    print('index:' + str(i) + ' 通貨:' + d)

$ python3 test.py
index:0 通貨:ドル
index:1 通貨:ユーロ
index:2 通貨:ポンド
index:3 通貨:リラ

Python bytearray()

bytearray() method returns a bytearray object which is an array of given bytes.

prime = [2, 3, 5, 7]

print(bytearray(prime))

$ python3 test.py
bytearray(b’\x02\x03\x05\x07′)

0 <= x < 256 の整数

Python 関数を数字(数字コード)で実行する方法

def OP_NOP():
    print("This is OP_NOP, 76")

def OP_IF():
    print("This is OP_IF, 99")

def OP_NOTIF():
    print("This is OP_NOTIF, 100")

OP_CODE = {
    76: OP_NOP,
    99: OP_IF,
    100: OP_NOTIF
}

func = OP_CODE[76]
func()

$ python3 test.py
This is OP_NOP, 76

bitcoinのOPcode一覧はこちら
https://en.bitcoin.it/wiki/Script

めちゃくちゃお洒落な書き方だな~

Python if not condition

a = True

if not a:
    print('a is false')

in String

a = ''

if not a:
    print('a is empty')
def mul(num):
    if type(num) == int:
        print(num * 2)
        return True
    else:
        return False

n = 'a'
if not mul(n):
    print('please input number')

if notは基本的にTrue or Falseを判定している

PythonのLogging

シンプルなログ出力はお馴染みのprint文

print("I am the simplest log.")

ファイル出力、メール送信、HTTP通信など動作ログをよりフレキシブルに出力したい場合にはloggingモジュールを使用してログを出力する。

### ログレベル
DEBUG, INFO, WARNING, ERROR, CRITICAL

出力

import logging 

logging.info("info log")
logging.warning("warning log")

$ python3 test.py
WARNING:root:warning log

info はコマンドラインに出力されない
loggerオブジェクトを取得してログを出力する

import logging 

logger = logging.getLogger("sample")
logger.info("info log")
logger.warning("warning log")

$ python3 test.py
warning log

import logging 

logger = logging.getLogger("sample")
logger.setLevel(logging.DEBUG)
logger.info("info log")
logger.warning("warning log")

### ハンドラ
StreamHandler, FileHandler, SMTPHandler, HTTPHandlerがある

import logging 

logger = logging.getLogger("sample")
logger.setLevel(logging.DEBUG)


st_handler = logging.StreamHandler()

logger.addHandler(st_handler)
logger.info("info log")
logger.warning("warning log")

handlerで指定することでログ出力をカスタマイズできる。

Python stackのpopとpush

class MyStack:
    def __init__(self):
        self.stack = []
    
    def push(self, item):
        self.stack.append(item)

    def pop(self):
        pass

mystack = MyStack()
mystack.push(0)
mystack.push(1)
mystack.push(2)
print(mystack.stack)

$ python3 test.py
[0, 1, 2]

pop

    def pop(self):
        result = self.stack[-1]
        del self.stack[-1]
        return result

print(mystack.pop())
print(mystack.pop())

取り出して削除なので、[-1]の後にdelを実行している。
上記と同じことをpop()と書くことができる。

    def pop(self):
        return self.stack.pop()

stackが0の場合があるので、例外処理も書かなければならない。

    def pop(self):
        if len(self.stack) == 0:
            return None
        return self.stack.pop()