1つだけ過去を変えられるとしたら?

AB 4.23.00を使用しています。

今回、ネットワークのプログラムの勉強を始め、とりあえず、
ネットワークを通して、ソフト間で簡単なチャットが出来るものを作ってみようと思い、作り始めました。

以前、CreateMailslot関数などで出来ると思い、探し回ったのですが、どうしても出来ないので、質問させていただいたところ、『それでは出来ない』とのこと(http://oshiete1.goo.ne.jp/qa5833366.html)だったので、
新たな方法を探していたところ、ソケットというものを使えば出来るというようなことが書かれているページを見つけ、早速参考にさせていただいています。

ですが、どうも、構造というか、その辺がよく分かっていないので、
どこにどの値をどう入れればいいのか・・・などがよく分かりません。

送信用のプログラムは、おそらく書けていると思いますが(一応貼らせていただきます)、
受信用のプログラムでちょっとつまずいています。
connect関数の接続先はどう指定すればいいのか、ということです。

ご存知の方、いらっしゃいましたら、ご教授の方、お願いします。

【送信用】
#console
#include <api_winsock2.sbp>

Declare Function bind Lib "wsock32.dll" (s As Long,ByRef sName As sockaddr,namelen As Long) As Long
Declare Function listen Lib "wsock32.dll" (s As Long,backlog As Long) As Long
Declare Function accept Lib "wsock32.dll" (s As Long,ByRef addr As sockaddr,ByRef addrlen As Long) As Long

Dim wsaData As WSADATA
WSAStartup(MAKELONG(2,0),wsaData)
Print "WSAStartup--->"+Date$()+" "+Time$()

Dim s As DWord
s=socket(AF_INET,SOCK_STREAM,0)

If s=0 Then
Print "Error-------->Cannot Socket Create"
Sleep(-1)
End If

Dim sar As SOCKADDR

With sar
.sa_family=AF_INET
End With

If bind(s,sar,Len(sar))<>0 Then
Print "Error-------->BIND ERROR"
Sleep(-1)
End If

Dim sarlen As Long
Dim news As DWord

listen(s,128)
news=accept(s,sar,sarlen)

Dim buf[256] As Byte
recv(news,buf,256,0)

send(news,"HELLO",lstrlen("HELLO"),0)

closesocket(s)
closesocket(news)

Print "SENDED"
Sleep(-1)


-----------------------------------------------------------------


【受信用(途中まで)】
#console
#include <api_winsock2.sbp>

Declare Function bind Lib "wsock32.dll" (s As Long,ByRef sName As sockaddr,namelen As Long) As Long
Declare Function listen Lib "wsock32.dll" (s As Long,backlog As Long) As Long
Declare Function accept Lib "wsock32.dll" (s As Long,ByRef addr As sockaddr,ByRef addrlen As Long) As Long


Dim wsaData As WSADATA
WSAStartup(MAKELONG(2,0),wsaData)
Print "WSAStartup--->"+Date$()+" "+Time$()

Dim s As DWord
s=socket(AF_INET,SOCK_STREAM,0)

If s=0 Then
Print "Error-------->Cannot Socket Create"
Sleep(-1)
End If

Dim sar As SOCKADDR

With sar
.sa_family=AF_INET
End With

If bind(s,sar,Len(sar))<>0 Then
Print "Error-------->BIND ERROR"
Sleep(-1)
End If

Dim sock_sin As SOCKADDR_IN
With sock_sin
.sin_family=AF_INET
End With

If connect(s,sock_sin,Len(sock_sin))<>0 Then
Print "Error-------->connect ERROR"
Sleep(-1)
End If

A 回答 (3件)

>結局listenで接続待ちになっていないようで、すぐにacceptの方に移ってしまい、


>acceptでエラーを返してきます。

動きとしてはそれであっています(実際此方でも同じです)
私が確認したのも listen 関数で該当ポート接続待ちにした状態で Sleep(-1) 関数コールして
その時にツールから接続が出来るか確認しただけです
(動いていない時接続エラー・動かしてる時接続OKの確認しただけ)
その後の動作(プログラミング)はActiveBasicでどのようにやればいいのかわからなかったので・・・・

> Do Loopで抑えておかないといけないのでしょうか?

普通は(かどうか知りませんが大抵の書籍などでは)
その後は SelectSocket 関数などを使ってイベント待ち状態として
イベントがコールされた時そちらの関数から Accept/Read/Write 等の関数を
コールしていると思います
(実際私もそのような使い方しかしたことがありませんが やり方によってコールバック関数でもいいかもしれません)

これは基本的には 永久ループで accept 呼び続けるのと同じことになるのではないかと思います
(いかんせんやったこと無いので自信なし)

あくまでCとしてのサンプルになりますが
(以下VCで作ったソケット部分の切り貼り 単純に切り貼りしてるので大文字小文字入り乱れてます)

メイン側で
  Listen();
  WSAAsyncSelect(SockSrv, hwnd_maindlg, WM_USERSOCKET_OFFSET, FD_ACCEPT | FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);// 非ブロッキング型


上記 hwnd_maindlg 側で

ON_MESSAGE(WM_USERSOCKET_OFFSET, OnSocketEvent)

void C***::OnSocketEvent(WPARAM wParam, LPARAM lParam)
{
  switch (WSAGETSELECTEVENT(lParam)){
  case FD_ACCEPT:
    Accept();
    break;
  case FD_READ:break;
  case FD_WRITE:break;
  case FD_CONNECT:break;
  case FD_CLOSE:break;
  default:break;
  }
}

といったような感じです


でもって今改めてみたけど質問者さんが書いたコードでポート開放できてるみたいでした
    • good
    • 0

構文(文法)も知らないのにやってみました


以下のコードでサーバポートが待ち受け状態になることまでは確認しました
(クライアントが接続に成功することを確認)

また気が向いたら調べるかもしれないけどあまり期待はしない方がいいです
(ここまでで物好きにも数時間かかったので・・・・・さすが文法知らず)
テストその他で要らないプリント文などもそのまま載せてますが削除してください

Declare Function bind Lib "ws2_32.dll" (s As DWord,ByRef name As SOCKADDR_IN,namelen As Long) As Long
Declare Function listen Lib "ws2_32.dll" (s As DWord,backlog As Long) As Long
Declare Function accept Lib "ws2_32.dll" (s As DWord,ByRef addr As SOCKADDR_IN,ByRef addrlen As Long) As Long

Dim wsaData As WSADATA

print wsaData.wVersion
WSAStartup(MAKELONG(2,2),wsaData)
Print "WSAStartup--->"+Date$()+" "+Time$()
print wsaData.wVersion

Dim s As DWord
s=socket(AF_INET,SOCK_STREAM,0)

Print s, AF_INET, SOCK_STREAM

If s=0 Then
Print "Error-------->Cannot Create Socket"
Sleep(-1)
End If

Dim sar As SOCKADDR
Dim sar_in As SOCKADDR_IN

Print sar_in.sin_family
FillMemory(VarPtr(sar_in),Len(sar_in),0)   ------ クリアが必要
Print sar_in.sin_family

With sar_in
.sin_family=AF_INET
.sin_port=htons(2000)       -------- とりあえずポート2000でサービス動作
                  ------- 1024以下は予約されてるので使ってはいけません
rem .sin_addr=htonl(0.0.0.0)    ----- サーバ側なのでとりあえず不要
                  ----- クライアントでは inet_addr を使います
End With

With sar
.sa_family=AF_INET
End With

If bind(s,sar_in,Len(sar_in))<>0 Then
Print "Error-------->BIND ERROR"
Sleep(-1)
End If

Dim sarlen As Long
Dim news As DWord

Print "Listn Start"

If listen(s,1)=SOCKET_ERROR Then
Print "Error-------->LISTEN ERROR"
Sleep(-1)
End If


接続確認として以下のツールを使用しました
http://download.goo.ne.jp/software/contents/soft …
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
調べていただき、本当にありがとうございます。

早速、とりあえず、実行の方をさせていただいたのですが、
どうも、listenの部分がよくわかりません。
acceptの前まで上書きさせていただいたのですが、
結局listenで接続待ちになっていないようで、すぐにacceptの方に移ってしまい、
acceptでエラーを返してきます。

これは、実は正しいのでしょうか?
Do Loopで抑えておかないといけないのでしょうか?
すいませんが、お願いします。

お礼日時:2010/04/25 00:26

コネクトできたらそのままsendでデータ送信できるはすです



但し記載コードでは其処まで動いていないと思います
クライアント側ではサーバのIPとポート指定してソケット開かないと
動きませんよ

単純なコードの問題ではなくてソケット通信というのがどんな物か
勉強された方がいいのではないかと思います
http://yonex1.cis.ibaraki.ac.jp/~yonekura/2002ka …

この回答への補足

サーバー側

#console
#include <api_winsock2.sbp>

Declare Function bind Lib "wsock32.dll" (s As Long,ByRef sName As sockaddr_in,namelen As Long) As Long
Declare Function listen Lib "wsock32.dll" (s As Long,backlog As Long) As Long
Declare Function accept Lib "wsock32.dll" (s As Long,ByRef addr As sockaddr,ByRef addrlen As Long) As Long

Dim wsaData As WSADATA
WSAStartup(MAKELONG(2,0),wsaData)
Print "WSAStartup--->"+Date$()+" "+Time$()

Dim s As DWord
s=socket(AF_INET,SOCK_STREAM,0)

If s=0 Then
Print "Error-------->Cannot Create Socket"
Sleep(-1)
End If

Dim sar As SOCKADDR
Dim sar_in As SOCKADDR_IN

With sar_in
.sin_family=AF_INET
.sin_port=htons(10000)
.sin_addr=htonl(0.0.0.0)
End With

With sar
.sa_family=AF_INET
End With

If bind(s,sar_in,Len(sar_in))<>0 Then
Print "Error-------->BIND ERROR"
Sleep(-1)
End If

Dim sarlen As Long
Dim news As DWord

If listen(s,1)=SOCKET_ERROR Then
Print "Error-------->LISTEN ERROR"
Sleep(-1)
End If

news=accept(s,sar,sarlen)

If news=INVALID_SOCKET Then
Print "Error-------->ACCEPT ERROR"
End If

Dim buffer[1024] As Byte
Dim bErr As Long
bErr=recv(news,buffer,1024,MSG_OOB)

If bErr=0 or SOCKET_ERROR Then
Print "Error-------->RECV ERROR AS "+Str$(bErr)
Sleep(-1)
End If

closesocket(s)
closesocket(news)

補足日時:2010/04/21 17:17
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

リンク先のページ、拝見させていただきました。
目を通しながら、書き直しているのですが、サーバー側のlisten関数で、接続待ちになりません。(SOCKET_ERRORがすぐに返る)

それと、bind関数で、第二パラメータは『SOCKADDR』型となっていますが、
『SOCKADDR_IN』型を、どうやって指定するのでしょう?
とりあえず、Declareの定義部分で変えてやっています(これがいけないのかと思いますが・・・)

すみませんが、よろしくお願いします。

お礼日時:2010/04/21 17:16

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!