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のままテストしました。
次回はクライアント側で。


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です