|
|
2007/3/22(Thu) 19:13:26|NO.6493
こんにちは
ネット系ソフトを作っています。
前はTCPで作ったのですがデータの送受信が遅くリアルタイム性がないので
UDPでデータ送受信するように考えていますが
UDPクライアントからUDPサーバにデータは送れてるのですが
サーバからクライアントにデータが送れません
どうすればいいですか?
udpsendto "IPアドレス",ポート番号ってありますが
クライアントの方はサーバのIPとポート番号を設定していますが
サーバの方はクライアントのIPとポートを設定するのですか?
一応UDPサーバはクライアントから送られてきたデータを現在繋がっている
クライアントに送るのみです
#include "pcbnet2.as"
#include "hspda.as"
;
; UDP通信サンプル(サーバー)
;
dim soc,16
dim soc2,16
port = 12346 ;// ポート12346で待機
title "UDP サーバーテスト"
udpsock soc,port
if stat : dialog "ソケットの初期化に失敗しました。",1 : end
;udpsendto "ipアドレス",port ←たぶんここに入れるんだとおもいます
onexit *bye
sdim buf,100,15
buf=str(buf)
msg=str(msg)
*main
udpcheck a,soc
if a : gosub *recv
wait 1
goto *main
*recv
cls
udpget buf,64,soc ;データ受信
sdim getd,128,4
getd=str(getd)
csvsel buf
csvstr getd,buf
dd=int(getd.0);どのクライアントからのデータか確認
pos 0,20*dd
mes buf
udpput buf,soc ;接続されているクライアント分送らないとダメですよね
return
*bye
udpclose soc
end
tcpと同じく繋がっているクライアントリストを製作しないとダメですか?
PS:
udpマルチのスクリは作ったのですが今ひとつD範囲と言うのがわからないので
C/S形式にしました
|
|
2007/3/22(Thu) 19:22:11|NO.6495
UDPマルチのスクリについてですが、
Hsファイルには
マルチキャストアドレスとは,IPアドレスのうちDクラスの範囲(224.0.0.0〜
239.255.255.255)のアドレスです.
ただし,特別な用途の通信でない場合は,なるべく239.255.0.0〜239.255.255.255を
この中から見ると、
例として、"239.255.0.0"と"239.255.255.255"があります。
このどちらかを使えば
マルチのスクリは出来るはずです。
そっちの方がいくらから楽と思います。(少なくとも僕の場合は。)
|
|
2007/3/22(Thu) 19:33:27|NO.6496
>>AKIさん
UDPの概念にサーバー・クライアントという分け方はありません。
TCPを使った事ある人は混乱すると思いますが;
考え方としてはTCPでセッションを引いて、接続リストを作成してUDPで送受信です。
(もちろん、UDPは信頼性が低いので重要な送受信は抜く)
今、ご飯食べてるので後ほどサンプルスクリプト載せます;
|
|
2007/3/22(Thu) 21:39:31|NO.6500
まず、サーバーの方を
#include "common.as"
#include "pcbnet2.as"
title "Server - TCP&UDP"
cls 4
/*変数初期化*/
// サーバー用変数
dim _LISTEN_, 1
// ソケット構造(数値)
// 配列に情報をいれていく
// 0 = フラグ
// 1 = TCPソケットID
// 2 = TCPポート(相手の)
// 3 = 待機フラグ
// 4 = UDPソケットID
// 5 = UDPポート(自分の)
// 6 = UDPポート(相手の)
dim _SOCK_, maxUSER, 6
// ソケット構造(文字列)
// 0 = IP
sdim _SOCKs_, 256, maxUSER
/*まず、セッション(TCP)用を開きます。*/
tcpmake _LISTEN_, PORT
if (stat != 0) {
end
}
*MAIN
/*新着セッションと接続状況取得*/
gosub *CHECK
gosub *RECV
gosub *EXQ
;gosub *SEND
wait 1
goto *MAIN
*CHECK
tcpwait _LISTEN_
if (stat != 0) {
/*セッション要求があったら*/
tcpaccept DUMMY, _LISTEN_
: i = -1
repeat maxUSER
if (_SOCK_(cnt) == 0) {
/*iに空いている番号を教える*/
: i = cnt
break
}
loop
if (i == -1) {
/*もしiが-1のままなら*/
tcpshut DUMMY
tcpclose DUMMY
} else {
/*空いていたら*/
: _SOCK_(i, 0) = 1
: _SOCK_(i, 1) = DUMMY
/*IP:PORTを取得*/
sdim pINFO, 256
tcpinfo pINFO, _SOCK_(i, 1)
/*IP*/
getstr _SOCKs_(i), pINFO, 0, ':'
/*PORT*/
getstr pINFO, pINFO, strsize, ':'
: _SOCK_(i, 2) = int(pINFO)
: _SOCK_(i, 3) = 0
/*UDPソケットの生成*/
udpsock _SOCK_(i, 4), 0
if (stat != 0) {
end
}
/*自分のポート取得*/
// のちにサーバーに知らせる用
//
udpport _SOCK_(i, 5), _SOCK_(i, 4)
/*PIDの送信*/
tcpput ""+(_REQ_+_PID_)+"3\n"+(_GET_+_SOC_)+"\n", _SOCK_(i, 1)
}
}
repeat maxUSER : n = cnt
/*接続フラグチェック*/
if (_SOCK_(n, 0) == 1) {
/*維持なら*/
tcpfail _SOCK_(n, 1)
if (stat != 0) {
/*切断なら*/
tcpshut _SOCK_(n, 1)
tcpclose _SOCK_(n, 1)
udpclose _SOCK_(n, 4)
/*空いていたら*/
: _SOCK_(n, 0) = 0
}
}
loop
return
*RECV
repeat maxUSER : n = cnt
/*受信チェック*/
if (_SOCK_(n, 0) == 1) {
/*変数初期化*/
: _SOCK_(n, 3) = 0
// 0 = 受信
// 1 = 送信
sdim _BUF_, 1024, maxUSER, 2
/*受信状況の取得*/
tcpcount pSIZE, _SOCK_(n, 1)
if (pSIZE > 0) {
tcpget _BUF_(n, 0), pSIZE+1, _SOCK_(n, 1)
/*受信したらフラグを1へ*/
: _SOCK_(n, 3) = 1
}
}
loop
return
*EXQ
repeat maxUSER : n = cnt
/*受信していたら*/
if (_SOCK_(n, 3) == 1) {
notesel _BUF_(n, 0)
repeat noteinfo(0) : i = cnt
/*文字列取得*/
noteget a, i
: pCMD = strmid(a, 0, 3)
: pTEXT = strmid(a, 3, strlen(a))
switch int(pCMD)
//
// UDPソケットの設定
case (_SET_+_SOC_)
/*udpソケットのポートを受け取る*/
: _SOCK_(n, 6) = int(pTEXT)
udpsendto _SOCK_(n, 4), _SOCKs_(i), _SOCK_(n, 6)
udpput "OK 受信されました", _SOCK_(n, 4)
swbreak
//
// それ以外
default
swbreak
swend
loop
noteunsel
}
loop
return
やっていることは TCP で確実なセッションを引いています。
そして、クライアントにUDPのポート番号を聞いています。
IPはTCPinfoから取得しているので分かっています。
そして、UDPで返信しています。
| |
|
2007/3/22(Thu) 21:41:49|NO.6501
次にクライアントです。
#include "common.as"
#include "pcbnet2.as"
title "Client - TCP&UDP"
cls 4
/*変数初期化*/
// クライアント用変数
// 0 = ソケットID
// 1 = ポート
// 2 = 待機フラグ
dim _TCP_, 3
dim _UDP_, 3
/*まず、セッション(TCP)用を開きます。*/
tcpopen _TCP_(0), IP, PORT
if (stat != 0) {
end
}
udpsock _UDP_(0), 0
if (stat != 0) {
end
}
/*自分のポート取得*/
// のちにサーバーに知らせる用
//
udpport _UDP_(1), _UDP_(0)
*MAIN
gosub *CHECK
gosub *RECV
gosub *EXQ
gosub *SEND
wait 1
goto *MAIN
*CHECK
/*接続状態取得*/
tcpfail _TCP_(0)
if (stat != 0) {
/*切断なら*/
tcpshut _TCP_(0)
tcpclose _TCP_(0)
end
}
return
*RECV
/*変数初期化*/
: _TCP_(2) = 0
// 0 = 受信
// 1 = 送信
sdim _BUF_, 1024, 2
/*受信状況の取得*/
tcpcount pSIZE, _TCP_(0)
if (pSIZE > 0) {
tcpget _BUF_(0), pSIZE+1, _TCP_(0)
/*受信したらフラグを1へ*/
: _TCP_(2) = 1
}
/*追加*/
sdim _PAK_, 1024
udpcheck pSIZE, _UDP_(0)
if (pSIZE > 0) {
udpcount pSIZE, _UDP_(0)
udpget _PAK_, pSIZE+1, _UDP_(0)
dialog ""+_PAK_
}
return
*EXQ
/*受信していたら*/
if (_TCP_(2) == 1) {
notesel _BUF_(0)
repeat noteinfo(0) : i = cnt
/*文字列取得*/
noteget a, i
: pCMD = strmid(a, 0, 3)
: pTEXT = strmid(a, 3, strlen(a))
switch int(pCMD)
//
// PIDの応答
case (_REQ_+_PID_)
: pid = int(pTEXT)
swbreak
//
// UDPソケットの取得
case (_GET_+_SOC_)
: _BUF_(1) = ""+(_SET_+_SOC_)+""+_UDP_(1)+"\n"+_BUF_(1)
: _TCP_(2) = 2
swbreak
//
// それ以外
default
swbreak
swend
loop
noteunsel
}
return
*SEND
if (_TCP_(2) == 2) {
tcpput _BUF_(1), _TCP_(0)
}
return
TCPでサーバーとのセッションを引き、PIDを取得してUDPポートを返します。
あとはUDPを使って取得・送信すればおけです。
少々複雑ですが、少しずつ分解してみてください。
| |
|
2007/3/22(Thu) 21:51:48|NO.6502
で、最後に共通設定のヘッダーです。
/*共通仕様の宣言*/
#define global IP "127.0.0.1"
#define global PORT 3301
#define global maxUSER 8
#define global _REQ_ 200
#define global _SET_ 400
#define global _GET_ 600
#define global _PID_ 001
#define global _SOC_ 002
急ぎだったので、サーバー側に送信処理がなかったりしてます。
あとはクライアントにUDPの送信処理ないです。
恐らく、聞いているのは「クライアントのポートをサーバー教えるには?」だと思います。
これは udpport を使って 「クライアント側で取得してTCPでサーバーに送信する」が解決策です。
マルチキャストも有効ですが、できるだけLAN内だけにした方がいいです。
そこはTCPを参考に出来ると思うのでがんばってみてください。
|
|
2007/3/23(Fri) 08:34:17|NO.6504
おはようございます
アキスさん
マルチで作った場合にソフトを配布するときにクライアント側での設定がわからないのでパスしました。
93さん
理解するのに少々時間かかります
一応、現在はTCPサーバとUDPサーバがありクライアント接続があるとTCPサーバで
リストに追加してその番号をクライアントに返してからUDPサーバにデータを送っています
info命令で所得した"215.94.144.25:8080"をIPとportに分けるのはどうすれば良いですか?
csvstrは","区切りでの分割なので分け方がわかりません
|
|
2007/3/23(Fri) 12:02:42|NO.6508
> AKIさん
少々、複雑すぎました;
IP:PORTの分け方はサーバーのスクリプトに書いてありますが
sdim pINFO, 256
tcpinfo pINFO, SOCK
/*IP*/
getstr IP, pINFO, 0, ':'
/*PORT*/
getstr PORT, pINFO, strsize, ':'
です。
|
|
2007/3/23(Fri) 12:48:10|NO.6512
こんにちは93さん
とりあえず
<pre)
udpsock soc,port
if stat : dialog "ソケットの初期化に失敗しました。",1 : end
udpget buf,64,soc ;データ受信
sdim getd,128,4
getd=str(getd)
csvsel buf
csvstr getd,buf
dd=int(getd.0);どのクライアントからのデータか確認
sdim pINFO, 256
udpinfo pINFO,soc
/*IP*/
getstr ip, pINFO, 0, ':'
/*PORT*/
getstr po, pINFO, strsize, ':'
という風にしています
クライアントからのデータbuf(先にTCPサーバで割り振った番号,aデータ,bデータ)
繋がっているクライアントにすべて送るには
ipとportを配列変数に入れて送るのですか?
udpsendto soc.cnt,ip.cnt,port.cnt
udpput buf,soc.cnt
と言う風にすれば良いですか?
|
|
2007/3/23(Fri) 14:48:31|NO.6514
>>AKIさん
送信する方法は udpsendto soc.cnt,ip.cnt,port.cnt : udpput buf,soc.cnt であってます。
データbufはサーバーで加工したバッファでしょうか?
それとも、クライアントからのデータでしょうか?
もし後者なら、サーバー側でパケット構築し直してから送信し直す必要があります。
UDPは順序補償がないので順序補償するのと、何度もudpputするのは効率的ではないので全てのユーザーのデータbufをパッキングします。
パッキングしたものを上記の方法で「一度の送信」で同期させます。
|
|
2007/3/23(Fri) 19:54:56|NO.6526
こんにちは93さん
後者のクライアントからのデータです。
サーバでサーバー側でパケット構築し直すとはどういうことですか?
少しスクリ変えてみましたけどエラーがでます
#include "pcbnet2.as"
#include "hspda.as"
;
; UDP通信サンプル(サーバー)
;
sdim ip,255,16
dim po,16
sdim buf,255,16
dim soc,16
dim soc2,16
port = 12346 ;// ポート12346で待機
title "UDP サーバーテスト"
udpsock soc,port
if stat : dialog "ソケットの初期化に失敗しました。",1 : end
*main
udpcheck a,soc ;クライアントからデータが来たら*revへ
if a:goto *rev
wait 1
goto *main
*rev
udpget buf,64,soc ;データ受信
sdim getd,128,4
getd=str(getd)
csvsel buf
csvstr getd,buf
dd=int(getd.0) ;どのクライアントからのデータか確認
sdim pINFO, 256
udpinfo pINFO,soc
/*IP*/
getstr ip.dd, pINFO, 0, ':'
/*PORT*/
getstr po.dd, pINFO, strsize, ':'
po=int(po)
repeat 15
udpsendto soc.cnt,ip.cnt,po.cnt ;繋がっているクライアントに送信先指定
udpput buf,soc.cnt ;クライアントにデータ送信
wait 1
loop
goto *main
としましたがudpsendto soc.cnt,ip.cnt,po.cntがパラメータエラーになります
どの変数がおかしいかわからなくなりました
むずかしい
|
|
2007/3/23(Fri) 20:14:15|NO.6527
>>AKIさん
ざっとみた感じでは
/*PORT*/
getstr po.dd, pINFO, strsize, ':'
po=int(po)
変数poは数値型なのにgetstr取得時は文字列だからエラー?と思ってます。
あと、その下のpoだとpo.0なのでpo.ddではないです。
だから、getstr時は一時的な文字列変数が必要だと思います。
|
|
2007/3/23(Fri) 21:41:30|NO.6531
> サーバでサーバー側でパケット構築し直すとはどういうことですか?
パケット1個につき要求が一回のとは限りません。また、悪意あるパケットかもしれません。
なので、受け取ったパケットを検証したり最適化するためです。
サーバーではクライアントの要求を分解して他のクライアントに配る専用のパケットも作る必要があります。
一度の要求に対して結果を一度の送信で終わらせるのが鉄則です。
(何回もudpputやtcpputを呼ぶのは危険かつ無駄です)
ここだけの話tcpが遅いと言っても1ms~5ms程度のなのでHSPじゃあまり変わらない気がします。
それよりも補間技術の作った方が良い気がします。
|
|
2007/3/24(Sat) 09:10:29|NO.6542
おはようございます
/*PORT*/
getstr po.dd, pINFO, strsize, ':'
po=int(po)
を一応
dim ppp,16
/*PORT*/
getstr po.dd, pINFO, strsize, ':'
ppp.dd=int(po.dd)
repeat 15
pos 0,20*cnt
mes buf.cnt
udpsendto soc,""+ip.cnt,ppp.cnt
udpput buf.cnt,soc
wait 1
loop
にしたら動いたのですが0番ののデータがクライアントに届きません
とりあえず、TCPサーバとUDPサーバとクライアントソフトを載せます
TCPサーバ: http://akihide.no-ip.com/TCPServer.hsp
UDPサーバ: http://akihide.no-ip.com/udpServer.hsp
クライアント: http://akihide.no-ip.com/Client.hsp
です
TCPだけのソフトは掲示板の
http://hsp.tv/play/pforum.php?mode=pastwch&num=3065にあります
|
|
2007/3/24(Sat) 12:16:19|NO.6543
>> AKIさん
気になったのはUDPサーバー側ではudpsockが1つしか生成されていません。(しかも、固定ポート
1:1の場合は良いのですが、1:nの場合は間違ってます。
pcbnetでは
TCPは自動的にtcpacceptで複数のソケットが管理されます。(tcpmakeで出来た親sidとtcpacceptで出来る子sid)
UDPではソケットを自分で管理しなくてはいけません。(全てが親sid)
通信プログラムは 作りたいモノ によって変わるので私も助言しづらいですね。
なので、
一度手を休めて専門的なサイトなどを見てどんなシステムがあるのか調べることをおすすめします。
|
|
2007/3/24(Sat) 16:20:41|NO.6546
udpsockは1:1なんですね
わかりました。
とりあえず自分でコツコツしてみます
ありがとう
|
|
2007/4/10(Tue) 11:54:34|NO.7221
荒らされたんですね(−−;
|
|