Python de socket(2)
ノンブロッキングで
前回のつづきですが、
そう、ググってみるとわかりますが、
最後は、selectを使うのが正解!
みたいに書いてありますけどね。
Pythonのselectも使ったことないので、
とりあえず、ノンブロッキングで例外拾ってやってみましょう。
ノンブロッキングにするのは簡単で、次の1行
s.setblocking(False)
ですね。
で、やってみるとどうなるかっていうと、、
まずサーバ側から。
●Windowsの場合
BlockingIOError: [WinError 10035] ブロック不可のソケット操作をすぐに完了できませんでした。
■Linuxの場合(ここではCentOS)
BlockingIOError: [Errno 11] Resource temporarily unavailable
ということで、TryCatchを入れてみます。
try:
conn,addr = s.accept()
except Exception as e:
en = e.args[0] # self.getWinErrorN(e)
print("en:",en)
● Windowsの場合
en: 10035
■Linuxの場合
en: 11
ということでこれを拾ってLOOPしましょ
例外を拾ってLOOP
print("〇accept開始")
while True:
try:
conn,addr = s.accept()
break
except Exception as e:
en = e.args[0]
if en == 10035:
print("10035")
time.sleep(0.1)
continue
elif en == 11:
print("11")
time.sleep(0.1)
continue
結果は、当然こうなります。
ということで、Acceptはこんなもんでしょ。
recieveは?
recieve(recv)はちょっと考えましょう。
というのは、recvで読み込めたからと言って、
それでホントに終わりなの?
っていうのを確認したいわけで。
そうすると、
LOOP
例外1
例外2
読み込めた
読み込めた
例外3
みたいなときに、例外3のところで終了したいわけです。
そう、
acceptに成功したからといって、すぐそのあとのrecvが成功するとは限らない
ってとこがポイントです。
逆に、sendの場合はだいたい成功しますけど、だいたいをプログラムでやっちゃいけないので、そこもちゃんとしましょ。
conn.setblocking(False) #LINUXだとこれをしないとrecvがblockingしてしまう。Windowsは無くて良い
print("〇recv")
recV = b''
while True:
try:
dat = conn.recv(4)
recV = recV + dat
print("〇dat",dat)
except Exception as e:
if recV != b'':
break
en = e.args[0]
print("en:",en)
残念ながら成功してしまいました。
●Windowsの場合
10035
10035
10035
〇recv
〇dat b’1234′
〇dat b’5674′
〇dat b’8901′
〇dat b’2345′
〇dat b’6789′
〇dat b’0′
recV: b’123456748901234567890′
〇10秒後に終了
■Linuxの場合
11
11
11
11
〇recv
〇dat b’1234′
〇dat b’5674′
〇dat b’8901′
〇dat b’2345′
〇dat b’6789′
〇dat b’0′
recV: b’123456748901234567890′
〇10秒後に終了
SRCにも書いてありますけど、Linuxは、connectionの方にもBlockingしないとアカンようです。
この部分 ➡ conn.setblocking(False)
sendは?
recvと違ってsendは、何やら成功しちゃう場合が多く、エラーをあえてださせるのも大変です。
sendは送信できたバイト数がとれるので、それをチェックして、成功するまでLOOPさせましょ。
print("〇send")
mes = b"I am Hiraide"
sendn = len(mes)
nn = 0
while True:
try:
a = conn.send(mes[nn:])
print("send bytes:",a)
nn = nn + a
if nn >= sendn:
break
except Exception as e:
en = e.args[0]
print("en:",en)
time.sleep(0.01)
結果:(Windows,Linuxとも)
〇send
send bytes: 12
まとめ
ということで、サーバ側は、こんな感じでした。
今回のクライアント側は、Blockingのままテストしました。
次回はクライアント側で。