出産前後の痔にはご注意!

クライアント(Windows)とサーバ(Unix)とSocket通信をするアプリを作っています。処理内容はクライアントのデータファイルをサーバに送信(アップデイト)し、サーバ側でデータを解析し、その結果を印刷するという手順です。
WinSockを使って、送信そのものはうまくいくのですが、サーバでデータを解析し結果を印刷するのに時間がかかり(10秒以上)、その間は送信終了のイベントが発生しません。これはサーバ側での処理を exec関数とwait関数で行っているので、正しい事態なのですが、データの送信が終わったら後はサーバ側で勝手にやって欲しいのです。サーバでの処理を system関数に置換えたり、バックグランド処理にしてもやはり処理が終わるまで送信終了のイベントが発生しません。何かいい方法をお教えください。

このQ&Aに関連する最新のQ&A

A 回答 (4件)

なるほどー


うーむ難しいですねー

Winsock1.SendData HogeHoge
DoEvents
とすると、どうですか?

またはサーバーが解析処理に入る前に、DoEventsみたいなものをUNIX側で実行することは無理ですか?
非同期で実行はしているけど、その解析処理が占有しているために、クライアントに届かないなんてことは無いですか?

すいません。かなり推測でお話をさせていただいてます。_(._.)_

この回答への補足

いろいろと一緒に考えてくださってありがとうございます。

サーバ側ではデータの受信後ソケットを閉じているのでそれ以外の処理は思いつきません。それにクライアント側がMS-DOSで作ったアプリは現在運用中ですが、データ送信後すぐに終了しているので、やはりクライアント側の問題かなと思ったり。

それで、
Winsock1.SendData HogeHoge
DoEvents
の、HogeHoge って何ですか?

サーバ側がcloseしてから送信することになるとエラーになると思いますが、
サーバの状況をチェックするために何か送信するのはいいテストだと思います。
クライアント側で、自主的にWinSock1_Close を発行するのは、サーバ側で処理が正常に行われず失敗しました。
でもクライアント側で何かアクションする方向をまだ模索してみたいと思います。

補足日時:2002/03/09 00:54
    • good
    • 0
この回答へのお礼

いろいろとありがとうございました。
まだ解決していませんが、データ送信後のホスト側での処理をリモートシェルで行う方法を検討しています。アクセス権の問題など別の問題が発生していますが何とか格闘してみます。

お礼日時:2002/03/17 10:33

UNIXについては、最低限の知識しかありません。



ですのでよくわかってないのですが。。。

送信は新たなソケットを作成して行ってますよね?
そうすると通常はWinSock1_Closeイベントが発生するように思えるのですが・・・

UNIXで受け専用のロジックでもあるのですか?

この回答への補足

サーバ側(UNIX)では常時ソケットは接続要求を待っています(listen)。クライアント側が接続要求すると受け入れOKなら接続番号を返し(accept)、通信が始まります。通信が完了するとクライアント側が切断要求をだすことにより、サーバ側がこの接続番号のソケットを閉じます。(close)
そのあとクライアント側でWinSock1_Closeイベントが発生します。
データのやり取りだけならこれで問題ないのですが、サーバ側で受信したデータを解析処理したり色々な仕事を非同期で実行しています。だから問題ないはずなのですが、なぜか非同期で実行している仕事が終わるまで、クライアント側のWinSock1_Closeイベントが発生しません。サーバ側のCloseを発行している時刻を調べると受信が終わってすぐ発行しているので、クライアント側ですぐに終われるはずなので、何かWinSockの設定の問題なのか、サーバとクライアントのどちらに問題があるのか、手がかりが見つかりません。途方にくれています。

補足日時:2002/03/08 20:54
    • good
    • 0

>信終了のイベントが発生しないというのは、


>Closeイベントが発生しないということです。

どうもWindowsとUnix間通信ではWinSockのCloseイベントは
発生しないようです。

以下のURLの「コラム:WinSock」でも見てください。

参考URL:http://research.nii.ac.jp/~ichiro/lecture/syspro …

この回答への補足

ありがとうございます。
サーバでの処理が終われば Close イベントは発生しているので、問題の多くはサーバ側の処理にあるのだと思います。
「コラム:WinSock」参考にさせていただきます。
これから仕事先に行って試行錯誤をしてみます。

補足日時:2002/03/07 12:37
    • good
    • 0
この回答へのお礼

いろいろとありがとうございました。
まだ解決していませんが、データ送信後のホスト側での処理をリモートシェルで行う方法を検討しています。アクセス権の問題など別の問題が発生していますが何とか格闘してみます。

お礼日時:2002/03/17 10:33

もう解決されたかもしれませんが。



>その間は送信終了のイベントが発生しません。
クライアントで、SendCompleteイベントが発生しないということですか?

解決方法として、サーバから応答電文をクライアントに送信するという
ことではどうですか?それくらい考えたわいと怒られそうですが。

この回答への補足

いいえ、解決していません。
送信終了のイベントが発生しないというのは、
Closeイベントが発生しないということです。

もともとこのアプリは、クライアント(Ms-dos)サーバ(Unix)でやりとりしていたのをクライアント側だけWindows用に作り変えています。socket通信のサーバ側のソフトはそのまま利用していて、独自のプロトコル(データのやりとりの手順が決まっているので)でやりとりしている中でサーバ側のCloseはデータ受信後すぐ発行されているのですが、exec関数で実行している処理が終了するまで待っている感じです。

お返事がいただけて嬉しかったです。もう少しいろいろ試してみます。

補足日時:2002/03/07 10:31
    • good
    • 0

このQ&Aに関連する人気のQ&A

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

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qwinsock通信時エラーの回避

winsock通信でデータをクライアント側からサーバー側に送り、一定の条件でサーバー側からクライアント側にデータを戻すソフトを作成中なのですが、サーバー側が通信エラーの為か止まってしまいます。

サーバー側(winsock部分)記述

Private Sub Winsock1_Error(Index As Integer, ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)

Winsock1(Index).Close '接続を閉じる
Do While Not (Winsock1(Index).State = sckClosed)
DoEvents
Loop

On Error Resume Next
Winsock1(Index).Listen
If Winsock1(Index).LocalPort <> 0 Then
Winsock1(Index).LocalPort = 0

End If

End Sub


質問の整理ですが、
表示板にはギミックが付いておりそのギミックは止まらないのでパソコンのフリーズでは無い様子です。
で問題は通信部分だと推測されるのですが、そのエラーを起こした通信を破棄してもいいので、サーバー側の点数加算を止めない方法はありませんでしょうか。
また上記のWinsock1_Errorコードの記述じゃおかしいのでしょうか。

winsock通信でデータをクライアント側からサーバー側に送り、一定の条件でサーバー側からクライアント側にデータを戻すソフトを作成中なのですが、サーバー側が通信エラーの為か止まってしまいます。

サーバー側(winsock部分)記述

Private Sub Winsock1_Error(Index As Integer, ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)

Winsock1(Index).Close '接...続きを読む

Aベストアンサー

現象が発生するのはまれでしょうか?

試してみましたがクライアントから連続してconnectすると発生しやすいようです。
ただ、このエラーが発生しても、特に異常が見られないので、このエラーを無視してはどうでしょうか?

Private Sub Winsock1_Error(Index As Integer, ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)

If Index = 0 Then ' 受け付けるポートと接続するポートは処理が違う
If Number <> 10035 Then ' エラーコード10035は、無視
Winsock1(Index).Close '接続を閉じる
Do While Not (Winsock1(Index).State = sckClosed)
DoEvents
Loop
On Error Resume Next
Winsock1(Index).Listen
End If
Else
Winsock1(Index).Close '接続を閉じる
Do While Not (Winsock1(Index).State = sckClosed)
DoEvents
Loop
Unload Winsock1(Index)
closedSocks.Add Index
End If

End Sub

現象が発生するのはまれでしょうか?

試してみましたがクライアントから連続してconnectすると発生しやすいようです。
ただ、このエラーが発生しても、特に異常が見られないので、このエラーを無視してはどうでしょうか?

Private Sub Winsock1_Error(Index As Integer, ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)

If Index = 0 Then ' 受け付けるポートと...続きを読む

QVBのソケット通信(winsock)のサイト

VBでwinsockコントロールを使ってソケット通信にて、データの送受信をするプログラミングをするのですが、サンプルコードなどが載っているサイト、わかりやすく説明してあるサイトがありましたら教えてください。

Aベストアンサー

ここの履歴にサンプルが載ってます。。。
っていうか載せました。

わかりやすいかどうかは、わかりませんが・・・

参考URL:http://oshiete1.goo.ne.jp/kotaeru.php3?q=155606

QTCP/IP通信でのコネクションロスト(ソケットエラー)の検知について

インターネット上での対戦ゲームの作成を行なっているところです。
サーバーを挟んでクライアント間で双方向の通信を行なっています。

 A → サーバー → B
 A ← サーバー ← B

TCP/IPは信頼性の高い通信方法ということで、データ抜けなどは
心配しなくても良いと聞いています。
もし、データ抜けなどが発生した場合はコネクションロストの状態になると。

実際のプログラミングではソケットを使用しています。
コネクションロストが起きると、ソケットエラーかソケットクローズで検知できます。


実際に例えばクライアントAを強制終了させるとサーバーはただちに
ソケットクローズを検知します。


ここで、問題はデータを送っても届かないのに、
ソケットエラーもソケットクローズも起きない状態が発生することです。
これはインターネットの経路上になにか問題が発生したと考えていますが
このような状態はタイムアウトなどで監視する以外に検知する方法はないのでしょうか?


クライアントはウィンドウズでVB6.0のwinsockを、
サーバーはLinuxを使用しています。

なにかアドバイスをいただければありがたいです。

インターネット上での対戦ゲームの作成を行なっているところです。
サーバーを挟んでクライアント間で双方向の通信を行なっています。

 A → サーバー → B
 A ← サーバー ← B

TCP/IPは信頼性の高い通信方法ということで、データ抜けなどは
心配しなくても良いと聞いています。
もし、データ抜けなどが発生した場合はコネクションロストの状態になると。

実際のプログラミングではソケットを使用しています。
コネクションロストが起きると、ソケットエラーかソケットクローズで...続きを読む

Aベストアンサー

>>これはインターネットの経路上になにか問題が発生したと考えていますが
>>このような状態はタイムアウトなどで監視する以外に検知する方法はないのでしょうか?

多くのアプリは、タイムアウトで処理しているようです。例えば、経路途中のどこかのLANケーブルが抜けて通信が失敗した場合、すぐにエラーを検出して異常になるよりも、LANケーブルを差し込んだら、そのまま継続してくれるほうが嬉しいわけですからね。

もし、デフォルトのタイムアウトがいやなら、定期的に信号をやりとりする仕組みを組み込めばいいと思います。ただし、そのやりとり自体もタイムアウトになる可能性があるのと、連番を振って管理するなどしてエラー時の再送をやる場合、考慮無くやると、アホな結果を生む可能性もあるので、注意が必要です。このあたりの話題はソケット関係の情報を検索すると出てくると思います。

あまり厳密にやると複雑化する気もするので、シンプルにタイムアウトでの対処がいいかなと思います。

QSocketのSend関数でのCLOSEの検知 [Linux]

Linux環境でSocket(dm:PF_INET,type:SOCK_STREAM)を使用しての、
Client&ServerプログラムをCで作成しているのですが、
そこでのSend関数の使い方についてご助力ください。

Client&Serverプログラムは下記のような動きをします。

[Client]
ServerへConnectした後、複数のDataを数秒間隔でServerへ
送信(send関数使用)します。受信(recvやread関数等)は、
一切行いません。

[Server]
ClientからのConnectを受け付けた後、Clientから受信(recv関数
使用)したDataを標準出力へ表示する。送信(sendやwrite関数
等)は、一切行いません。


さて、ここでもしClientプログラムがCloseを発行したり、マシン
DOWN等の理由でConnectionが切断され、Server側のSocketが
CLOSE_WAIT状態になった場合、Bufferに溜まっていたDataを
すべて受けきった後、recv関数が0を返してくれるので
相手が終了したことがわかります。

ここからが質問のMainです。

では、もしServerプログラムがCloseを発行したり、マシン
DOWN等の理由でConnectionが切断され、Client側のSocketが
CLOSE_WAIT状態になっても、CLOSE_WAIT直後のsend関数が
なぜか正常に処理されてしまいます。無論このDataは、
Server側は受け取りません。この次のsend関数実行時に
EPIPEが返ってくるので、ここでようやくSocketが切断された
ことが判ります。

これを何とかCLOSE_WAIT状態になった直後から、send関数で
切断を検知できるようにできないでしょうか。

よろしくお願いします。

以上

Linux環境でSocket(dm:PF_INET,type:SOCK_STREAM)を使用しての、
Client&ServerプログラムをCで作成しているのですが、
そこでのSend関数の使い方についてご助力ください。

Client&Serverプログラムは下記のような動きをします。

[Client]
ServerへConnectした後、複数のDataを数秒間隔でServerへ
送信(send関数使用)します。受信(recvやread関数等)は、
一切行いません。

[Server]
ClientからのConnectを受け付けた後、Clientから受信(recv関数
使用)したDataを標準出力へ表示する。送信(se...続きを読む

Aベストアンサー

#3です。
>完全な保証ではないのですが、”送れた/送れない”をきちんと
ログとして残す必要があるのです。

なるほど、そういう事情でしたか。それだと、それなりの信憑性が要求されますね。

>それと最初にご提案いただいたrecvをNonBlockモードで呼び出す
方法ですが、これだとrecvのリターン値は0が返ってこないでしょうか?

Linuxで以下のような、プログラムを組んで確認しました。

//送信前に、ノンブロッキングでrecvする。
ret = recv(sock,rbuf,sizeof(rbuf),MSG_DONTWAIT);
if (ret == -1 && errno == EAGAIN){
//正常なので送信可能
ret = send(sock,msg[i],sendlen,0);
if (ret != sendlen){
//送信エラーの処理
}
}else{
//切断検知時の処理
 // CLOSE_WAITになると ret=0が返る
}

サーバー側で切断時、直ちにrecvで戻り値=0となり、エラーの検知ができました。ret==-1 かつ errno==EAGAIN
であれば、回線は正常状態です。

#3です。
>完全な保証ではないのですが、”送れた/送れない”をきちんと
ログとして残す必要があるのです。

なるほど、そういう事情でしたか。それだと、それなりの信憑性が要求されますね。

>それと最初にご提案いただいたrecvをNonBlockモードで呼び出す
方法ですが、これだとrecvのリターン値は0が返ってこないでしょうか?

Linuxで以下のような、プログラムを組んで確認しました。

//送信前に、ノンブロッキングでrecvする。
ret = recv(sock,rbuf,sizeof(rbuf),MSG_DONTWAIT);
if (ret == -...続きを読む

Qネットワーク切断を検出するには?

Linux上で動作するTCP/IP通信アプリケーションが、LANケーブル抜けによるネットワーク切断を検知するにはどうしたらよいのでしょうか?

外部からコネクションを確立した後にケーブルが抜けたとき、Linux側でソケットをcloseしたいのです。今はこれができておらず、接続状態のまま(netstatでみるとESTABLISHED)になっています。複数の接続を許していないので、ケーブルを繋いだあとにTCP/IPで再接続できません。

試したこと
ソケットに対するioctl(2)でifreq.ifr_flagsのIFF_UPフラグをみたけど検知不可
切断時にselect(2)がエラーリターンするかと思ったがだめ

ケーブルが抜けたとき、カーネルが eth0: link down とログに出力するのでどこか(/proc , /sys以下)を参照すればよさそうな気がするんですが…

Aベストアンサー

HP-UXなので微妙に異なる可能性はありますが、こんな感じです。
http://docs.hp.com/ja/B2355-60129/TCP.7P.html

Qexeファイルのセキュリティ。

社内用のメンテナンスプログラムを制作したのですが、同じプログラムで他社の製品にも使えてしまいます。たいした大きさではないので、フロッピーで十分なんですが社外に流失してしまうとこまってしまいます。
IPアドレスで確認すればいいのですが、登録していないようなものはどうしたらよいのでしょうか?
どなたか、教えていただけませんか?

Aベストアンサー

通信認証のサンプルを作成しました。
(正確に言うと、以前に作成したものがあって、それを抜粋しました)

プロジェクトは二つ必要で、サーバーとクライアントに分かれています。
それぞれにプロジェクトを作成して、EXEを作成してください。
基本はサーバーのEXEが立ち上がった状態で、クライアントのEXEを起動してください。
この書き込みの下の方に「共通の標準モジュール」を記してますが、[INIT_PORT][SERVER_NAME]の各定数があります。
こちらは環境に合わせて変更をしてください。
もし、一台のマシンで実験をするのであればSERVER_NAMEをご自分のマシン名に変更をしてください。

プログラムが正常に動くと、サーバー、クライントが交互に通信状況をメッセージボックスで知らせます。
これはあくまでサンプルなのでそのようにしてますが、サーバー側にはメッセージボックスの機能を使用しないでください。メッセージボックスが表示されている間は、他のユーザーとの通信ができなくなってしまいます。
(VBでそれを回避する方法があるのですが、動作が不安定になるために書きません)

このサンプルでは、互いに文字列を送信しています。
実践では、その文字列をパスワード認証に使用してはいかがでしょうか?



必要なもの

Project1.vbp(サーバー用)
フォーム
Winsock1(インデックスなし)
Winsock2(インデックスあり)

Project2.vbp(クライアント用)
フォーム
Winsock1(インデックスなし)

Winsockはメニューバーより
[プロジェクト]
[コンポーネント]
[Microsoft Winsock Control 6.0(かな?)]
を選択したらツールボックスにWinsockコントロールが現れます。
それをサーバー側に二つ、クライアント側に一つ、各フォームに貼り付けます。
サーバー側のWinsock2にはIndexプロパティに'0'ゼロをセットしてください。
その他のWinsockには値を入力しないでください。

あとは下のソースを貼り付けてください。
-----サーバーのフォーム内のソース(ここから)---------
Option Explicit

Private Sub Form_Load()
  Me.Caption = "SERVER"

  'ポートの初期化を行い、受信待ち状態にする
  On Error GoTo PGMERR
  
  With Me.Winsock1
    .LocalPort = INIT_PORT
    .Listen
  End With
  
  Exit Sub
  
PGMERR:
  Call MsgBox("通信ポートに以上が見られました、終了いたします。", vbSystemModal, Me.Caption)
  End
End Sub

'フォームが閉じる前に、Winsockを全て閉じる
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
  Dim wkSock As Winsock
  
  With Me
    .Winsock1.Close
    For Each wkSock In .Winsock2
      wkSock.Close
    Next wkSock
  End With
End Sub

'特定のクライアントのソケットを閉じたとき
Private Sub Winsock2_Close(Index As Integer)
  With Me
    .Winsock2(Index).Close
    Unload .Winsock2(Index)
  End With
End Sub

'メッセージデータの受信
Private Sub Winsock2_DataArrival(Index As Integer, ByVal bytesTotal As Long)
  Dim strRecvData As String    '送られてきたデータ
  Dim lngRecvCnt As Long     '送られてきたデータライン数
  Dim valRecvAry As Variant   '送られてきたデータをライン数のに分解し配列にして記憶
  
  Dim wkVal    As Variant   '受信したメッセージ1文を、IDとメッセージに分解して配列で記憶
  Dim wkSType   As SOCKMSG_ID  '分解した1文のID
  Dim wkStr    As String    '分解した1文のメッセージ
  
  Dim i      As Long     'ループカウンタ
  
  Dim wkMsg    As String    '送信するメッセージ
  
  With Me
  
    'メッセージを受け取る
    .Winsock2(Index).GetData strRecvData
    
    '受信メッセージを、メッセージ分の配列にする
    valRecvAry = Split(strRecvData, vbCrLf)
    
    'メッセージ数を取得
    lngRecvCnt = UBound(valRecvAry)
    
    '受信メッセージの分だけ、一文ずつ処理を行う
    For i = 0 To lngRecvCnt - 1
    
      '一文をIDとメッセージに分解
      wkVal = Split(valRecvAry(i), vbNullChar)
      wkSType = wkVal(0)
      wkStr = wkVal(1)
      
      Select Case wkSType
        Case SOCKMSG_ID.ID1
          wkMsg = "山川豊"
          Call MsgBox("ID1で[" & wkStr & "]を受信しました" & vbNewLine & vbNewLine _
            & "ID1で[" & wkMsg & "]を送信します", vbSystemModal, Me.Caption)
          Call SendMsg(.Winsock2(Index), ID1, wkMsg)
          
        Case SOCKMSG_ID.ID2
          wkMsg = "起動してもいいよ"
          Call MsgBox("ID2で[" & wkStr & "]を受信しました" & vbNewLine & vbNewLine _
            & "ID2で[" & wkMsg & "]を送信します", vbSystemModal, Me.Caption)
          Call SendMsg(.Winsock2(Index), ID2, wkMsg)
      
      End Select
    Next i
  End With
PGMEND:
End Sub

'接続要求がきたら、新たなWinsockを用意する
Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long)
  Dim lngNewIndex As Integer
  
  lngNewIndex = 0
  On Error Resume Next
  
  With Me
    '新たな受信装置を1つ追加する
    Do
      Err.Clear
      lngNewIndex = lngNewIndex + 1
      Load .Winsock2(lngNewIndex)
    Loop Until Err.Number = 0&
    On Error GoTo 0
    
    .Winsock2(lngNewIndex).Accept requestID
  End With
End Sub
-----サーバーのフォーム内のソース(ここまで)---------

-----クライアントのフォーム内のソース(ここから)-------
Option Explicit

'フォームロード時に接続を試みる
Private Sub Form_Load()
  Me.Caption = "CLIANT"

  With Me.Winsock1
    .RemoteHost = SERVER_NAME
    .RemotePort = INIT_PORT
    .LocalPort = 0
    .Connect
  End With
End Sub

'サーバーが落ちた
Private Sub Winsock1_Close()
  Call MsgBox("サーバーが落ちたー", vbSystemModal, Me.Caption)
  Unload Me
End Sub

'サーバーと接続できた
Private Sub Winsock1_Connect()
  Dim wkMsg  As String
  
  wkMsg = "岸部四郎"
  
  Call MsgBox("接続できた" & vbNewLine & vbNewLine _
      & "ID1で[" & wkMsg & "]を送信します", vbSystemModal, Me.Caption)
  Call SendMsg(Me.Winsock1, ID1, wkMsg)
End Sub

'サーバーと接続できなかった
Private Sub Winsock1_Error(ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
  Call MsgBox("接続できなかった", vbSystemModal, Me.Caption)
  Unload Me
End Sub

'メッセージデータの受信
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
  Dim strRecvData As String    '送られてきたデータ
  Dim lngRecvCnt As Long     '送られてきたデータライン数
  Dim valRecvAry As Variant   '送られてきたデータをライン数のに分解し配列にして記憶
  
  Dim wkVal    As Variant   '受信したメッセージ1文を、IDとメッセージに分解して配列で記憶
  Dim wkSType   As SOCKMSG_ID  '分解した1文のID
  Dim wkStr    As String    '分解した1文のメッセージ
  
  Dim i      As Long     'ループカウンタ
  
  Dim wkMsg    As String    '送信するメッセージ
  
  With Me
  
    'メッセージを受け取る
    .Winsock1.GetData strRecvData
    
    '受信メッセージを、メッセージ分の配列にする
    valRecvAry = Split(strRecvData, vbCrLf)
    
    'メッセージ数を取得
    lngRecvCnt = UBound(valRecvAry)
    
    '受信メッセージの分だけ、一文ずつ処理を行う
    For i = 0 To lngRecvCnt - 1
    
      '一文をIDとメッセージに分解
      wkVal = Split(valRecvAry(i), vbNullChar)
      wkSType = wkVal(0)
      wkStr = wkVal(1)
      
      Select Case wkSType
        Case SOCKMSG_ID.ID1
          wkMsg = "鳥羽一郎"
          Call MsgBox("ID1で[" & wkStr & "]を受信しました" & vbNewLine & vbNewLine _
            & "ID2で[" & wkMsg & "]を送信します", vbSystemModal, Me.Caption)
          Call SendMsg(.Winsock1, ID2, wkMsg)
          
        Case SOCKMSG_ID.ID2
          Call MsgBox("ID2で[" & wkStr & "]を受信しました" & vbNewLine & vbNewLine _
            & "通信を終了します", vbSystemModal, Me.Caption)
          
          '''''ここに通信が正常にできたことを示すフラグを立てておく
          Unload Me
      End Select
    Next i
  End With
PGMEND:
End Sub
-----クライアントのフォーム内のソース(ここまで)-------

サーバー・クライアントのそれぞれに共通の標準モジュールとして、以下のソースを追加してください。
-----共通の標準モジュール(ここから)-------
Option Explicit

Public Enum SOCKMSG_ID
  ID1 = 1
  ID2 = 2
  ID3 = 3
End Enum
Public Const INIT_PORT As Long = 8000 '←このPORTは使用される確立が高いので、適当な値に変更したほうがいいかも?
Public Const SERVER_NAME As String = "PC_MACHINE_NAME" '←サーバー用のEXEのをおくマシン名

Public Sub SendMsg(inSock As Winsock, inSendType As SOCKMSG_ID, inSendMsg As String)
  Dim wkStr  As String
  
  With inSock
    '通信が可能なときに通信する
    If (.State = (sckConnected)) Then
      '通信の書式は
      ' 1.通信を送るときのID(SOCKMSG_IDを自分で作成、オリジナルの番号を振る)
      ' 2.vbNullChar(IDとメッセージとの区切り文字)
      ' 3.メッセージ(任意の文字列)
      ' 4.vbCrLf(文末を示す)
      wkStr = inSendType & vbNullChar & inSendMsg & vbCrLf
      
      'メッセージを送る
      .SendData wkStr
    End If
  End With
End Sub
-----共通の標準モジュール(ここまで)-------

通信認証のサンプルを作成しました。
(正確に言うと、以前に作成したものがあって、それを抜粋しました)

プロジェクトは二つ必要で、サーバーとクライアントに分かれています。
それぞれにプロジェクトを作成して、EXEを作成してください。
基本はサーバーのEXEが立ち上がった状態で、クライアントのEXEを起動してください。
この書き込みの下の方に「共通の標準モジュール」を記してますが、[INIT_PORT][SERVER_NAME]の各定数があります。
こちらは環境に合わせて変更をしてください。
もし、一台のマ...続きを読む

QWinsockを使わずにVBでSocketを利用したい

Winsockを使わずにVBでSocketを利用したいと考えています.事情がありましてコンポーネントを使わずにSocket通信でサーバープログラムと通信を行いたいです.
APIなどでSocket関係の関数は用意されているのでしょうか?
宜しくお願いします.


OS:Windows2000+SP4
Visual Basic 6.0+SP5

Aベストアンサー

ソケットで検索↓

参考URL:http://www.vbvbvb.com/jp/gtips/index.html

Qsocket: recvはいつ,どれだけ受け取るのか?

 現在,参考書にしたがってC++でソケットプログラミングを書いています.

 sendとrecvを非同期にするために,本では select関数やWSAAsyncSelect関数などを利用していて,実際,本のとおりに書いて上手く動いています.

 ここで伺いたいのですが,recvは,どうやって「データが届いたか」を知るのでしょうか.

 同期ならば,トランシーバでの会話のように送信側が「どうぞ」といって送受信を交代させることができますが,非同期ならばそれができません.

 NICとかが,プログラムに「届いたぞ!( or これから届くぞ!)」と教えてくれるのでしょうか.あるいは逆に,プログラムがNICに「届いてる?」と聞いているのでしょうか.仮に,ここに書いたような方法で届いたことが分かったとしても,どれくらい受け取ればいいかは分かりません(それも併せて教えてもらっているのでしょうか.データを送るときには,どれだけ送ればいいか分かりますよね.受信するときはどうしてるのかを知りたいと思っています).

Aベストアンサー

Linux しか知らないので Linux で説明をします。

NIC が通信パケットを受け取ると割り込みが発生し、CPU は割り込みを受け付けて、対応するデバイスドライバを起動します。この時、ドライバはソケットバッファと呼ばれる構造体にパケットの中身をコピーして、Linux カーネルの本体に渡し、そこで TCP 等の上位プロトコル処理が行われます。

一方、ユーザプログラムの方は、 select() なり read() で待っている訳ですが、OS はもちろんプロセスが何を待っているかを知っているので、対応する待ちの条件が満たされると、この場合は select() や read() が、抜けてくる(return する)訳です。

という事で、ユーザのプログラムは select() なり read() なりで受信データを「待つ」ことが必要です。もちろん select() や read() が呼ばれた時点で既に受信しているのならば、それらは直ぐに帰ってきます。read() や recv() はデータが届いた事を知る、というよりは、届いているかチェックして、まだ届いていなければ届くまで待つ(read() が抜けてこない)という処理になります。また NIC とユーザプログラムが直接やり取りをするのではなく、間にバッファがあって、対応するソケットのデータがある(受信済み)/ないか(未受信)、という問い合わせを行っているだけです。

ソケットの場合、データの送受信は非同期であり、送受信のタイミングのずれは(ソケット)バッファである程度吸収されます。もちろん、送受信バッファが満杯になった場合は流量制御が働いて、結果的に送信側の write() や send() が待ちに入ることになります。

Linux (Unix) のソケットの受信では、read() 等で指定されたバッファが常に満杯で返されるとは限らない設計になっています。つまり、その時に受信しているデータを返すだけなので、read() で返されたバイト数を必ず見ないと間違った動きになるので注意してください。

Linux しか知らないので Linux で説明をします。

NIC が通信パケットを受け取ると割り込みが発生し、CPU は割り込みを受け付けて、対応するデバイスドライバを起動します。この時、ドライバはソケットバッファと呼ばれる構造体にパケットの中身をコピーして、Linux カーネルの本体に渡し、そこで TCP 等の上位プロトコル処理が行われます。

一方、ユーザプログラムの方は、 select() なり read() で待っている訳ですが、OS はもちろんプロセスが何を待っているかを知っているので、対応する待ちの条件が満...続きを読む

QFTP対応のアプリケーション

INETコントロールを使って、サーバとファイルの送受信をするアプリを作りたいのですが、基本的なところでつまづいています。

サンプルプログラムを見つけたので試してみているのですが。
以下。

Private Sub cmdDownload_Click()
Dim GetBuf() As Byte
Dim FileNum As Integer

GetBuf() = Inet.OpenURL(txtURL.Text, icByteArray)
FileNum = FreeFile
Open txtSavePath.Text For Binary Access Write As FileNum
Put #FileNum, , GetBuf()
Close #FileNum
MsgBox "ダウンロード終了"
End Sub

ここで、txtURL.Text に何を記述したらいいのか、はっきり分かりません。
サーバー名にファイルのあるディレクトリを付けた形、
ftp://servername/home/tmp/test.txt
サーバーのIPアドレスにファイルのあるディレクトリを付けた形、
ftp://172.20.1.17/home/tmp/test.txt
を試してみたのですが、うまくダウンロードできません。

目的のプログラムは Executeメソッドを使ってファイルの送受信をしたいのですが、どちらにしてもURLの記述ができないとダメなのですよね?
どうぞ、よろしくお願いいたします。

INETコントロールを使って、サーバとファイルの送受信をするアプリを作りたいのですが、基本的なところでつまづいています。

サンプルプログラムを見つけたので試してみているのですが。
以下。

Private Sub cmdDownload_Click()
Dim GetBuf() As Byte
Dim FileNum As Integer

GetBuf() = Inet.OpenURL(txtURL.Text, icByteArray)
FileNum = FreeFile
Open txtSavePath.Text For Binary Access Write As FileNum
Put #FileNum, , GetBuf()
Close #FileNum
MsgBo...続きを読む

Aベストアンサー

ご指名ありがとうございます。(←変な飲み屋みたい)

こんな感じ?
  With Inet1
    .URL = "ftp://ftp.hoge.com"
    .UserName = "TAGOSAKU7"
    .Password = "内緒"
    .Execute , " DIR"
  End With

UserNameとPasswordは、ExecuteかOpenURLを発行すると同時に送られているようです。
UserNameが空状態であれば "anonymous"を送っているようです。

でも、
>"ftp://user:pwd@URL"
使用方法によってはいいと思いますよ。
画面にさえ表示しなければ・・・


それと、、、
受けのサーバのポートは特に意識する必要はないと思います。
WinSockでもないので、ソケットのことを考える必要もないし、手順を間違わなければサーバに設定を施さなくてもできると思います。

QWinSockを使ってのプリンタ接続・データ送信

現在LANで接続されたプリンタに文字列を印字させるプログラムを作成しているのですが、プリンタ側のIPアドレス、使用するポート(今回は1024という指定があったのでそれに設定)を設定し、印字処理をはしらせたのですが、そこでエラーが発生してしまいます。簡略化していますが、プログラムは

Private sckWinsock As Winsock

Set sckWinsock = Winsock1

sckWinsock.Protocol = sckTCPProtocol
sckWinsock.RemoteHost = "192.168.0.***"
sckWinsock.RemotePort = 1024
sckWinsock.LocalPort = 0

sckWinsock.Connect
strData = "テスト印字"
sckWinsock.SendData strData

sckWinsock.Close

エラーは

sckWinsock.SendData strData

ここで発生し、『指定したトランザクションまたは要求のプロトコルまたは接続状態に問題があります。』とでます。
PINGはちゃんと通りますし、プリンタ設定にあるテスト印字は問題なく機能するので、プリンタとの接続がまずいとは思えないのですが・・・
WinSockを使うのは初めてなので勝手がわからなく苦戦中です
どなたかわかる方、お返事お待ちしています

現在LANで接続されたプリンタに文字列を印字させるプログラムを作成しているのですが、プリンタ側のIPアドレス、使用するポート(今回は1024という指定があったのでそれに設定)を設定し、印字処理をはしらせたのですが、そこでエラーが発生してしまいます。簡略化していますが、プログラムは

Private sckWinsock As Winsock

Set sckWinsock = Winsock1

sckWinsock.Protocol = sckTCPProtocol
sckWinsock.RemoteHost = "192.168.0.***"
sckWinsock.RemotePort = 1024
sckWinsock.LocalPort = 0

sck...続きを読む

Aベストアンサー

APIを使用するとできます。
ただ、使い慣れるまでちょっと大変かも・・

ちょっと検索したら、以下のところにサンプルが
ありました。

winsock api なんかで検索してみてください。
ほとんどがC言語用にかかれているものばかりですけど。
がんばってください。

参考URL:http://www.int21.co.jp/pcdn/vb/noriolib/vbmag/9802/winsock/


人気Q&Aランキング