2017-12-09 16 views
0

私はUDP通信を起動しています。 シンプルなストライプ・ダウン・バージョンでは、クライアントは基本的に次のようにしています。(はい、多くのifとエラー・チェックがコード内にあり、いいえ、多くの定義はそのままでは機能しません。ここでは、実際のコードよりもconseptual)UDPとソケットがクライアントに応答しています

sock = socket(AF_INET, SOCK_DGRAM, 0); 
server_length = sizeof(struct sockaddr_in); 
sendto(sock, "Hi", 3, 0, (struct sockaddr *)&myaddr, server_length); 
numRes = recvfrom(sock, (char *)buff, (int)sizeof(buff), 0, (struct sockaddr *)&myaddr, &server_length); 

とサーバは、基本的には同じです:

sock=socket(AF_INET, SOCK_DGRAM, 0); 
bind(sock,(struct sockaddr *)&server,length); 
resBytes=recvfrom(sock,buff,(int)sizeof(buff),0,(struct sockaddr *)&from, &fromlen); 
sendto(sock, "Test",5, 0, (struct sockaddr *)&from, fromlen); 

これは動作します。両端は、相手側が送信するデータを受信します。

ここに私の問題があります:サーバーは、同時に多くの要求を処理する必要があります。メッセージのキューを作って、別のスレッドがそれを処理できるようにしてから、別のスレッドのクライアントに送り返します。私がこれを行うと、送信用の新しいソケットが作成され、メッセージの後に続く「送信元」と同じアドレスが使用されましたが、クライアントは受信しません。

UDPメッセージでの返信は、同じソケットで行う必要があることを理解していますか?

同じソケットを送受信に使用すると、3つのクライアントでメッセージを送信するとどうなりますか?処理が完了すると、ランダムな順序で応答します。これは使えますか?

私はクライアント上で "サーバー"を作ることができますが、私の推測では、どんなNATでもそのアイデアを速く打ち破ることができます。私が試みることを試みる何

は、多かれ少なかれ、この次のとおりです。この種のコードが動作する必要がある場合は

sock=socket(AF_INET, SOCK_DGRAM, 0); 
sock2=socket(AF_INET, SOCK_DGRAM, 0); 

bind(sock,(struct sockaddr *)&server,length); 
resBytes=recvfrom(sock,buff,(int)sizeof(buff),0,(struct sockaddr *)&from, &fromlen); 

sendto(sock2, "Test",5, 0, (struct sockaddr *)&from, fromlen); 

、私は戻って私のデバッグになりますが、これは当てはまらないように、今、それはそうです。

編集: 誰かがタグとして「マルチスレッド」を追加しました。マルチスレッドのことを忘れているなぜ私は同じ要求に迅速に応答しないのかを説明する。何かが必要な場合は、すべての通信を1つのスレッドで行うことができます。申し訳ありませんが、これは人々を混乱させるが、ここでの主な質問は次のとおりです。a)クライアント上に「サーバー」を定義することなく、別のサーバーに応答を送信できますか? b)そうでなければ、同じソックされた(IEクライアントA送信、クライアントB送信、クライアントB応答、クライアントA応答、クライアントA応答)のランダムな順番をどのように処理するでしょうか?

+0

ソケットは、複数のスレッドで共有することはできません。しかし、UDPはコネクションレスなプロトコルなので、別のソケットを使って送受信できます。 – user0042

+0

@ user0042: "*ソケットは複数のスレッドで共有することはできません。それはアクセスがどのように同期するかの問題です。 – alk

+0

@alkまあ、同期は別々のスレッドを使う目的を打ち負かしますか? – user0042

答えて

1

ソケットが接続されていない限り、複数のソースからデータを受信し、複数のピアにデータを送信することができます。つまり、ソケットを明示的または暗黙的にバインドしてからsendtorecvfrom(またはrecv)を使用すると、同じソケットを使用して複数のピアからデータを送受信できます。しかし、最初にconnectソケットを使用すると、接続されたip:ポートにバインドされたソケット、つまり通常はデータを受け取ったソケットと同じソケットからデータを受け取ることができます。

これをテストするには、単純にPythonサーバーを使用できます(Cと同じように動作します)。このサーバーは、sock1sock2の2つのソケットを作成します。これはsock1上のメッセージを受信し、第一sock2(元のメッセージを受信しなかったもの)、次いでsock1(元のメッセージを受信した1つ)を使用してバックメッセージを送信する:ピアとして

from socket import * 

sock1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) 
sock2 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) 

sock1.bind(('127.0.0.1',9999)) 
data,addr = sock1.recvfrom(1024) 
print("got '{}' from {}".format(data,addr)) 

sock2.sendto(b"send from sock2", addr) 
sock1.sendto(b"send from sock1", addr) 

を私たちは、クライアントに接続されているソケットを使用しています。connect + send)または未接続のソケット(すなわち無connectsendto):

from socket import * 

connected=False 
sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP) 
if connected: 
    sock.connect(('127.0.0.1',9999)) 
    sock.send('send from connected client') 
else: 
    sock.sendto('send from unconnected client',('127.0.0.1',9999)) 
while True: 
    data,addr = sock.recvfrom(1024) 
    print("got '{}' from {}".format(data,addr)) 

あなたが接続されたソケット(connected=True)でクライアントを実行した場合、あなたはそれが唯一のsock1バックからメッセージを取得することがわかります、ポートクライアントが接続されており、sock2は(暗黙的に)いくつかの他のアドレスにバインドされています:sock1が(明示的)IPにバインドされているため、クライアントが接続されていないソケットを使用している代わりに、場合

got 'send from sock1' from ('127.0.0.1', 9999) 

connected=False)それはsock1sock2の両方からのメッセージを受け取ります:

got 'send from sock2' from ('127.0.0.1', 44596) 
got 'send from sock1' from ('127.0.0.1', 9999) 
+0

ありがとうございました。これは私の質問に答えています。私が見る限りでは、私は2つのソケットから送り返して "接続されていない"ものを行います。その後、私のコードに何か問題があるはずです。 –

+0

@AslakBerby:クライアントとサーバの間でNATを実行するデバイスがある場合、通常、接続の両側からip、portからなるa *状態*を作成し、この状態に一致するパケットのみをサーバから渡します。この特定の例では、sock1から送信されたパケットはNATデバイスを通過しますが、sock2から送信されたパケットは一致する状態がないため破棄されます。ステートフルファイアウォールがNATを行っていなくても、ステートフルファイアウォールにも当てはまります。 –

+0

私はそれを実現し始めていました。今日のほとんどの家庭では、インターネットとの間に何らかの種類のNATがあるので、NATと連携して接続されたバージョンを使用するようにしなければなりません。すべてのUDPコードを同じクラスに移動し、ソケットを1つだけ使用しました。私は、複数のクライアントと接続できることを確認するためにいくつかのテストを行うだけです。 –

関連する問題