質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

12674閲覧

unity(C#)とpythonでのソケット通信ができずに困っています。

meJ15

総合スコア55

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/11/10 13:28

前提・実現したいこと

一つのパソコンを使ってpythonでリアルタイムに計算した結果をC#(unity)で受け取りたい。

そこでパイプ処理というものに行きつき、さっそくデモ用にpythonで送信し、それをほかのpythonのプログラムで受信することはできました。参考URL

このpythonの受信プログラムをunityでも使える形にしようとしています。

(pythonで送信して、C#で受信)送信側のpythonのプログラムは変えなくてよいはず?

しかし受信用のプログラムをC#にどう書き直せばよいのかわからず、とりあえず、ほかのサイトを見て実装だけしようと思いました。
このサイトをみて、SocketServer、Serverというスクリプトを作り、ポートを50007としても、デバックログには何も出力されずに挫折しました。

上の方法をあきらめ、
他のサイトのC#クライアントのページをみてunityで使えるように書きましたが下のようすぐ接続が切れてしまい、データが受け取れません。
TCPC#クライアント

発生している問題・エラーメッセージ

pythonから送られてくるデータをunityで逐次とりたいが、切断される。

該当のソースコード

これがpythonの受信プログラムです。
2秒おきに、データを受け取っているつもりです。
これならpythonで送信される値をとれることがわかりました。
これをC#出かければ最高なのですが、、、

python

1import socket 2import time 3import datetime 4 5HOST = '127.0.0.1' # The remote host 6PORT = 50007 # The same port as used by the server 7for i in range(10): 8 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 s.connect((HOST, PORT)) 10 11 s.send("Hallo".encode('utf-8')) 12 data = s.recv(1024) 13 s.close() 14 print ('Received', (data).decode('utf-8')) 15 time.sleep(2.0) //2秒おきにデータをもらうために 16 17

これを自分なりにunityで動くように考えたものが↓です。
(2秒おきとかは考えずに来たデータを蓄積する)

C#

1using UnityEngine; 2using System; 3using System.IO; 4using System.Net; 5using System.Net.Sockets; 6using System.Collections.Generic; 7 8public class Cserver : MonoBehaviour { 9 10 // Use this for initialization 11 void Start () { 12 13 var HOST = "127.0.0.1"; 14 var PORT = 50007; 15 var data = 0; 16 System.Net.Sockets.TcpClient tcp = 17 new System.Net.Sockets.TcpClient(HOST, PORT); 18 Debug.Log("サーバと接続した"); 19 20 //NetworkStreamを取得する 21 System.Net.Sockets.NetworkStream ns = tcp.GetStream(); 22 23 24 //読み取り、書き込みのタイムアウトを10秒にする 25 //デフォルトはInfiniteで、タイムアウトしない 26 //(.NET Framework 2.0以上が必要) 27 ns.ReadTimeout = 100000; 28 ns.WriteTimeout = 100000; 29 30 var sendMsg = "hallo"; 31 //サーバーにデータを送信する 32 //文字列をByte型配列に変換 33 System.Text.Encoding enc = System.Text.Encoding.UTF8; 34 byte[] sendBytes = enc.GetBytes(sendMsg + '\n'); 35 //データを送信する 36 ns.Write(sendBytes, 0, sendBytes.Length); 37 Debug.Log(sendMsg); 38 39 40 //サーバーから送られたデータを受信する 41 System.IO.MemoryStream ms = new System.IO.MemoryStream(); 42 byte[] resBytes = new byte[256]; 43 int resSize = 0; 44 do 45 { 46 //データの一部を受信する 47 resSize = ns.Read(resBytes, 0, resBytes.Length); 48 //Readが0を返した時はサーバーが切断したと判断 49 if (resSize == 1) 50 { 51 Debug.Log("サーバーが切断しました。"); 52 break; 53 } 54 //受信したデータを蓄積する 55 ms.Write(resBytes, 0, resSize); 56 //まだ読み取れるデータがあるか、データの最後が\nでない時は、 57 // 受信を続ける 58 } while (ns.DataAvailable || resBytes[resSize - 1] != '\n'); 59 //受信したデータを文字列に変換 60 string resMsg = enc.GetString(ms.GetBuffer(), 0, (int)ms.Length); 61 ms.Close(); 62 //末尾の\nを削除 63 resMsg = resMsg.TrimEnd('\n'); 64 Debug.Log(resMsg); 65 66 //閉じる 67 ns.Close(); 68 tcp.Close(); 69 Debug.Log("切断しました。"); 70 71 Console.ReadLine(); 72 Debug.Log(data); 73 74 } 75 76 // Update is called once per frame 77 void Update () { 78 79 80 } 81} 82 83

このC#のプログラムをunityで動かすと下のようになります。
unity

またpython側は下のようになります
!python側]

これがpythonの送信プログラムです。このプログラムは変える必要はないと思います。
pythonの送信側は将来的に0か1か2かを2秒おきぐらいに送信するだけなので今は1を連続して送信しています。

python

1import socket 2import threading 3import time 4import datetime 5 6HOST = '127.0.0.1' 7PORT = 50007 8INTERVAL = 1 # 測定間隔 9status = { "result" : "" } # 結果保存用 10 11# 測定実行用スレッドのクラス 12class MyThread(threading.Thread): 13 14 def __init__(self): 15 super(MyThread, self).__init__() 16 self.setDaemon(True) 17 18 def run(self): 19 for i in range(50): 20 result = str(1) 21 print (result) 22 status["result"] = result 23 time.sleep(INTERVAL) 24 25 26 # サーバを作成して動かす関数 27def socket_work(): 28 29 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 30 s.bind((HOST, PORT)) 31 s.listen(1) 32 33 while True: 34 conn, addr = s.accept() 35 print ('Connected by', addr) 36 data = conn.recv(1024) 37 print (data.decode('utf-8')) 38 conn.send(status["result"].encode('utf-8')) 39 conn.close() 40 41if __name__ == '__main__': 42 43 # スレッドの作成と開始 44 mythread = MyThread() 45 mythread.start() 46 47 # サーバを作成して動かす 48 socket_work()

このC#のプログラムがなぜ意図した動きをしないのか、
pythonの受信用のプログラムをC#に書き換えたいですが、うまくいきません。

C#では2秒おきぐらいにpythonから来るデータを2秒おきに確認してそれによってアニメーションさせようと考えています。いま、そのデータの受信ができずに手が止まってしまっています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

pythonの送信側ですが

python

1 while True: 2 conn, addr = s.accept() 3 print ('Connected by', addr) 4 data = conn.recv(1024) 5 print (data.decode('utf-8')) 6 conn.send(status["result"].encode('utf-8')) 7 conn.close()

このブロックがwhileとしてループするんですよね?
とすれば、送信側のTCPコネクションの動作としては
1.受信側プログラムからの接続を受け付け
2.受信側プログラムからのデータを受信
3.データの送信
4.コネクションの切断
この処理がループすることになります。

Unity側は
1.送信側へコネクションの接続要求
2.接続したら、データの送信
3.送信側からのデータを受信
の流れが1回実行されるような形になるかと思います。
(このスクリプトがどのようにアタッチされているのか分からないので1回だけ呼ばれると考えています)
このスクリプトを定期的に動作させるようにするか、一連の流れをループして動作し続けるようにする必要があるかと思います。

ただ、この通信であれば、TCPを使うよりUDPを使った方がすっきりしそうな気がします。
UDPであれば、コネクションレスなので、
・送信側は受信側が実行されているされていないに関わらずデータを投げ続ける。
・受信側は受信待ちして、データが来たら処理をする
だけになりそうです。

送信側

python

1import socket 2 3 HOST = '127.0.0.1' 4 PORT = 50007 5 6 client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 while True: 8 client.sendto(status["result"].encode('utf-8'),(HOST,PORT)) 9

受信側

C#

1 int LOCA_LPORT = 50007; 2 udp = new UdpClient(LOCA_LPORT); 3 udp.Client.ReceiveTimeout = 1000; 4 5 while(true) 6 { 7 IPEndPoint remoteEP = null; 8 byte[] data = udp.Receive(ref remoteEP); 9 string text = Encoding.UTF8.GetString(data); 10 Debug.Log(text); 11 } 12

肉付けは必要ですが、通信部分だけであれば、このような感じになるかと思います。

投稿2018/11/10 15:19

YAmaGNZ

総合スコア10242

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meJ15

2018/11/11 03:58

回答ありがとうございます。UDP通信を使ったほうが良いという提案ありがとうございます。 pythonのコードを while True: a = random.randrange(3) result = str(a) print(a) client.sendto(result.encode('utf-8'),(HOST,PORT)) time.sleep(2.0) として、2秒おきぐらいに0,1,2を送るようにしました。 C#(unity側) using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; public class UDP : MonoBehaviour { static UdpClient udp; IPEndPoint remoteEP = null; int i = 0; // Use this for initialization void Start () { int LOCA_LPORT = 50007; udp = new UdpClient(LOCA_LPORT); udp.Client.ReceiveTimeout = 2000; } // Update is called once per frame void Update () { IPEndPoint remoteEP = null; byte[] data = udp.Receive(ref remoteEP); string text = Encoding.UTF8.GetString(data); Debug.Log(text); Thread.Sleep(1000); } } として、おくられてくるデータをunity側でみることができました。 通信部分だけを書いていただいたのがすごく助かりました。 これから自分が望む動作をするように頑張りたいと思います。
YAmaGNZ

2018/11/11 06:22

UnityではUpdateの中で時間をかけるべきではなかったかと思います。 受信部分は別スレッドなりで実行しておき、その値をUpdate内でみるという形にするほうがいいのだとは思いますが、Unityに適した実装方法はちょっと分かりません。
meJ15

2018/11/11 07:20

C# public calss UDPの内部のupdate関数を void Update () { IPEndPoint remoteEP = null; byte[] data = udp.Receive(ref remoteEP); text = Encoding.UTF8.GetString(data); Debug.Log(text); } } として、 他のunityプログラムのupdate関数で a = int.Parse(UDP.text); として値を確保することにしました。
guest

0

おそらく両方のソースともクライアントのソースになっているので、両方ともサーバに接続しようとしているのが原因だと思われます。ソースを見る限り、サーバを立てる部分がありません。
送信側か受信側のどちらかをサーバとして実行しないと接続できません。参考にしたURLのサーバを作成して動かす関数を組み合わせたらうまくいくと思います。

投稿2018/11/10 14:06

fia

総合スコア57

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meJ15

2018/11/10 14:17

回答ありがとうございます。 今私は一番下のpythonのコード(サーバ用?)と一番上のpython(クライアント用)のコードで上手くやり取りできましたが、一番上のpythonコードをC#に書き換えがうまくできてないと考えています。 そのC#のプログラムが2番目です。 今やっているのはこの2番目のC#と一番下のpythonのプログラムの通信です。 一番下のpythonのコードのdef socket_work():という関数でサーバを作成しているつもりなのですが、 このソースはサーバーとして機能していないのでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問