python の socketクラスのTCP通信を利用して、文字列をUDP通信相手に送るプログラムと
受信プログラムを紹介します。(MicroPythonでも動作します。)
import socket # udp_receive.py
UDP_IP = "192.168.0.110"
UDP_PORT = 3001
sock=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
local_addr=(UDP_IP, UDP_PORT)
sock.bind(local_addr)
print("start udp receive")
SIZE = 128
while True:
msg, client_addr = sock.recvfrom(SIZE)
print(len(msg), "byte受信", end="")
s=msg.decode()
print(s, end="")
if s.startswith("Quit") : break
sock.close()
import socket # udp_send.py
UDP_IP = "192.168.0.110"
UDP_PORT = 3001
sock=socket.socket(socket.AF_INET, type=socket.SOCK_DGRAM)
print("ソケット生成")
SIZE = 128
sockSend=socket.socket(socket.AF_INET, type=socket.SOCK_DGRAM)
send_addr=(UDP_IP,UDP_PORT )#IPアドレスとポート番号
while True:
cmd=input("送信文字列/Quit>>")
cmd += "\n"
send_len=sockSend.sendto(cmd.encode('utf-8'), send_addr)
print(cmd, send_len, "byte 送信しました")
if cmd[0:4] == "Quit": break
sock.close()
import socket # pc_udp
import _thread
UDP_IP = "192.168.0.110"
UDP_PORT = 3001
sock=socket.socket(socket.AF_INET, type=socket.SOCK_DGRAM)
print("ソケット生成")
sock.bind( (UDP_IP , UDP_PORT) )
SIZE = 32
def receive_loop():
print("受信ループ開始")
while True:
msg,client_addr= sock.recvfrom(SIZE) #受信
print("受信情報:",type(msg), client_addr)
print(msg.decode(encoding='utf-8'), "を受信しました。")
thread_id = _thread.start_new_thread( receive_loop, ())
import time
time.sleep(1)
sockSend=socket.socket(socket.AF_INET, type=socket.SOCK_DGRAM)
sever_addr=(UDP_IP,UDP_PORT )#IPアドレスとポート番号
while True:
s=input("W/A/X/D/S/B/QUIT/Q==>").upper()
if s.startswith("W") :
cmd="Forward\r\n"
elif s.startswith("A") :
cmd="Left\r\n"
elif s.startswith("X") :
cmd="Back\r\n"
elif s.startswith("D") :
cmd="Right\r\n"
elif s.startswith("QUIT") :
cmd="ServerStop\r\n"
elif s.startswith("Q") :
break
else:
cmd="Beep\r\n"
#
send_len=sockSend.sendto(cmd.encode('utf-8'), sever_addr)
print(cmd, send_len, "byte 送信しました")
sock.close()
# Python のマルチキャスト送信の簡単なコード例
import socket
MCAST_GRP = "239.192.0.0"
MCAST_PORT = 59001
while True:
if input("Enter で送信 quitで終了>") == "quit" : break
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
message = "192.168.0.110,59002" # 送信文字列
sock.sendto(message.encode('utf-8'), (MCAST_GRP, MCAST_PORT))
print(f"'{message}' を {MCAST_GRP}:{MCAST_PORT} に送信しました。")
sock.close()
import socket
import struct
def receiveIpMulticast(multicast_group, portNo): #マルチキャスト
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # ソケットの作成
server_socket.bind(('', portNo)) # ソケットにアドレスをバインド
# マルチキャストグループに参加
# group = ipv4_inet_pton(multicast_group) # 引数のIPアドレス文字列に対応する4byteバイナリ取得(Micropythonの場合)
group = socket.inet_aton(multicast_group)
mreq = struct.pack('4sL', group, 0)
server_socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# 受信
data, addr = server_socket.recvfrom(1024) # データとアドレスを受信 (最大で1024 バイトのデータを受信)
print(f"受信: {data.decode('utf-8')} from {addr}")
# 上記結果例:「受信: 192.168.0.110,59002 from ('192.168.0.110', 51201)」戻り値addrで送信側のIPアドレスが得られる
return data
def receiveIpMulticast_new(multicast_group, portNo): #マルチキャスト
wlan = network.WLAN(network.STA_IF)
local_ip = ipv4_inet_pton(wlan.ifconfig()[0])
print(f"local_ip:{local_ip}")
group = ipv4_inet_pton(multicast_group)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', portNo))
mreq = struct.pack('4s4s', group, local_ip)
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
print(f"Multicast-----{multicast_group}:{portNo}-----Wait !!!")
#s.settimeout(5) # optional
try:
data, addr = s.recvfrom(1024)
print(f"Multicast-----receive data: {data.decode()} from {addr}")
s.close()
return data
except OSError as e:
print("Multicast receive failed:", e)
s.close()
return None
ip_port_bin = receiveIpMulticast("239.192.0.0", 59001) # 接続サーバIPアドレス受信
ip_port_a = ip_port_bin.decode('utf-8').split(',')
print(f"受信データ:{ip_port_bin.decode('utf-8')}")
ip=ip_port_a[0]
portnumber=int(ip_port_a[1])
print(f"Multicast Recive IP:PORT:{ip}:{portnumber}")
import socket
import network
import struct
from machine import Pin
import utime
import gc
SSID='〇〇'# Wifi用
PW = '〇〇〇'# 上記に接続するためのパスフレーズ
def wifi__connect():# STA(ステーション)モードで既存のWi-Fiに接続して、確定したらリターン
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PW)
while wlan.isconnected() == False:
print('Connecting to Wi-Fi AP')
utime.sleep(1)
#
wlan_status = wlan.ifconfig()
return wlan_status
target_pin = Pin(14,Pin.OUT) # 使用LED(GPIO14接続)利用の準備
onboard_led = Pin( "LED", Pin.OUT )
target_pin.high()# 外付けLED点灯
wlan_status = wifi__connect()# Wifi接続
print( f'''Connected!
Pico IP Address:{wlan_status[0]} Netmask:{wlan_status[1]}
Default Gateway:{wlan_status[2]} Name Server: {wlan_status[3]}''' ) # Wifi接続情報表示
utime.sleep(1)
target_pin.low()# 外付けLED消灯
#ユニキャスト初期化
udp_portNo=59154
udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_sock.bind(('0.0.0.0', udp_portNo))
udp_sock.setblocking(False) # ソケットをノンブロッキングモードに設定
print(f"UDP 受信待機中 (ポート {udp_portNo})...")
# ブロードキャスト送信の準備
BROADCAST_PORT = 59001
MESSAGE = f"{wlan_status[0]},{udp_portNo}"
MESSAGE = MESSAGE.encode('utf-8')
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)# ブロードキャストを有効にする
# 自身picoWのIPアドレスをブロードキャストで配信をUDP受信まで繰り返す
count=0
while True:
sock.sendto(MESSAGE, ('255.255.255.255', BROADCAST_PORT))
print(f"[{count}] BROADCAST Sent: {MESSAGE}")
try:
data, udp_addr = udp_sock.recvfrom(1024) # UDP ユニキャスト受信
print(f"受信: {data.decode('utf-8')} from {udp_addr}")
break # UDP受信でループ抜ける
except OSError:# 接続なしの時はここに来る
print("まだ接続なし。処理続行。")
utime.sleep(2)
count+=1
print(f"送信先アドレス:{udp_addr}が確定")
udp_sock.setblocking(True) # ソケットをブロッキングモードに戻す
count=0
while True:
udp_sock.sendto(b'\x01\x02\x03\x04\x05\x06\x07', udp_addr) # テスト用7バイト送信(ここでOSError: [Errno 113] EHOSTUNREACH)
utime.sleep(0.01)
count+=1
#gc.collect()
print(f"count:{count}") # この行をコメント化すると、エラーが少し減る
count=0
while True:
try:
udp_sock.sendto(b'\x01\x02\x03\x04\x05\x06\x07', udp_addr) # テスト用の7バイト送信
except OSError as e:
udp_sock.close() # 上記の送信で OSError: [Errno 113] があったら、ソケットを閉じる
print(e)
#gc.collect() # この2行は影響しない実験結果が得られました。
#utime.sleep(2)
udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # ソケットを作り直す。
udp_sock.bind(('0.0.0.0', udp_portNo))
utime.sleep(0.01) # 送信間隔
count+=1
print(f"count:{count}") # 送信回数の表示
以上の変更で140000000回以上の送信しましたが、止まることなく動作しました。上記と通信するPC側のコード(sensor2_client.py)を下記に示す。 下記をUnity用にしたC#コード
import socket
import struct
import time
def receiveBroadcast(portNo): #ブロードキャスト受信関数
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', portNo))
print("Waiting for broadcast...")
data, addr = s.recvfrom(1024)
print(f"Received: {data} from {addr}")
s.close()
return data
ip_port_bin = receiveBroadcast(59001) # 接続サーバIPアドレスとポート番号の受信
print(f"受信データ:{ip_port_bin}")
rec_data=ip_port_bin.decode('utf-8')
ip_port_a = rec_data.split(',')
udp_ip=ip_port_a[0]
udp_portNo=int(ip_port_a[1])
hostname=socket.gethostname()
locat_ip = socket.gethostbyname(hostname)
locat_ip='192.168.0.110'
print(f"このPCのIPアドレス:{locat_ip}")
send_message=f"{locat_ip},{udp_portNo}"
send_message=send_message.encode('utf-8')
#ユニキャスト
udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_sock.bind(('0.0.0.0', udp_portNo))
udp_sock.setblocking(False) # ソケットをノンブロッキングモードに設定
print(f"UDP 受信待機中 (ポート {udp_portNo})...")
# 自身の情報を送信して、受信できたら送信を止めます。
while True:
print(f"sendto( {send_message},{(udp_ip, udp_portNo)} )")
time.sleep(1)
udp_sock.sendto(send_message, (udp_ip, udp_portNo))
try:
# 返信の受信を試みる(ノンブロッキング)
data, addr = udp_sock.recvfrom(1024) # 1024バイトまで受信
print(f"受信データ:{data}")
break
except OSError as e:
pass # 受信なし
udp_sock.setblocking(True) # ソケットをブロッキングモードに戻す
count=1
while True:
data, addr = udp_sock.recvfrom(1024) # 1024バイトまで受信
print(f"{count}回目の受信データ:{data}")
count+=1
udp_sock.close()