|
|||||
<このサンプルの概要> ソケットAPIを使用したTCP/IPとUDP/IPのサンプルソースです。 このサンプルは、VB6のサンプルですがVBAの通信プログラミングでも参考になると思います。 TCP/IPのサンプルはクライアント側のサンプルとサーバー側のサンプルがあります。 このサンプルの仕様は、 ソケット接続、電文送信、電文受信、ソケット切断のみのシンプル構造になっていますので、 ソケットAPIを使用したプログラミングの基本を簡単に理解する事が出来ます。 このサンプルでは次のソケットAPIを使用しています。 1.WSAStartup 2.WSACleanup 3.socket 4.closesocket 5.connect ※TCP/IPクライアントの時 6.bind ※UDP/IPの時はbindを使用。 ※TCP/IPサーバの時はbind、listen、accept、WSAAsyncSelectを使用。 7.sendto ※UDP/IPの時 8.send ※TCP/IPの時 9.recv TCP/IPのサーバー側はソケットAPI以外にウィンドウAPIを使用しています。 ※クライアント側からの要求(イベント)を処理するため。 1.GetWindowLong 2.SetWindowLong 3.CallWindowProc ソケット関係のその他のツールやサンプルソースはこちらです。 このサンプルの通信テストでもこちらのツールを使用しました。 通信サンプルやツール(RS232C TCP/IP UDP/IP) ★フォームモジュール(Form1.frm) Option Explicit ' ソケット用定数 Private Const SOCKET_ERROR = -1 Private Const AF_INET = 2 Private Const SOCK_STREAM = 1 Private Const SOCK_DGRAM = 2 Private Const INADDR_ANY = 0 Private Const FD_READ = &H1 Private Const FD_ACCEPT = &H8 Private Const FD_CLOSE = &H20 ' ソケット初期化用構造体 Private Type WSADATA wVersion As Integer wHighVersion As Integer szDescription As String * 257 szSystemStatus As String * 129 iMaxSockets As Integer iMaxUdpDg As Integer lpVendorInfo As Long End Type ' ソケットアドレス(IPおよびポート番号) Private Type SOCKADDR sin_family As Integer sin_port As Integer sin_addr As Long sin_zero As String * 8 End Type ' ソケット初期化/終了API Private Declare Function WSAStartup Lib "wsock32.dll" _ (ByVal wVersionRequired As Long, ByRef lpWSAData As WSADATA) As Long Private Declare Function WSACleanup Lib "wsock32.dll" () As Long ' ソケットオープン/クローズAPI Private Declare Function socket Lib "wsock32.dll" _ (ByVal af As Long, ByVal socktype As Long, ByVal protocol As Long) As Long Private Declare Function closesocket Lib "wsock32.dll" _ (ByVal s As Long) As Long ' ソケットアドレスAPI Private Declare Function htons Lib "wsock32.dll" _ (ByVal hostshort As Long) As Integer Private Declare Function inet_addr Lib "wsock32.dll" _ (ByVal cp As String) As Long ' ソケット接続API Private Declare Function connect Lib "wsock32.dll" _ (ByVal s As Long, ByRef addr As SOCKADDR, ByVal addrlen As Long) As Long Private Declare Function bind Lib "wsock32.dll" _ (ByVal s As Long, ByRef addr As SOCKADDR, ByVal addrlen As Long) As Long Private Declare Function listen Lib "wsock32.dll" _ (ByVal s As Long, ByVal backlog As Long) As Long Private Declare Function accept Lib "wsock32.dll" _ (ByVal s As Long, ByRef addr As SOCKADDR, ByRef addrlen As Long) As Long Private Declare Function WSAAsyncSelect Lib "wsock32.dll" _ (ByVal s As Long, ByVal hWnd As Long, ByVal wMsg As Long, ByVal lngEvent As Long) As Long ' ソケット送信API Private Declare Function sendto Lib "wsock32.dll" _ (ByVal s As Long, ByRef buf As Byte, ByVal lngLen As Long, ByVal flags As Long, _ ByRef addr As SOCKADDR, ByVal addrlen As Long) As Long Private Declare Function send Lib "wsock32.dll" _ (ByVal s As Long, ByRef buf As Byte, ByVal lngLenlen As Long, ByVal flags As Long) As Long ' ソケット受信API Private Declare Function recvfrom Lib "wsock32.dll" _ (ByVal s As Long, ByRef buf As Byte, ByVal lngLen As Long, ByVal flags As Long, _ ByRef addr As SOCKADDR, ByVal addrlen As Long) As Long Private Declare Function recv Lib "wsock32.dll" _ (ByVal s As Long, ByRef buf As Byte, ByVal lngLen As Long, ByVal flags As Long) As Long ' ソケットハンドル(TCP/IPサーバー時に使用) Private lngSck As Long Private lngCli As Long ' クライアントからの接続要求はとりあえず一個だけ ' フォーム開始 Private Sub Form_Load() lngSck = SOCKET_ERROR End Sub ' フォーム終了 Private Sub Form_Unload(Cancel As Integer) Dim lngRtn As Long If lngSck <> SOCKET_ERROR Then ' ソケットクローズ closesocket (lngSck) ' ソケット終了 WSACleanup End If End Sub ' UDP/IPでの送信/受信 Private Sub Command1_Click() Dim lngRtn As Long Dim lngSck As Long ' ソケット初期化 Dim wsa_data As WSADATA lngRtn = WSAStartup(&H101, wsa_data) If lngRtn = SOCKET_ERROR Then Exit Sub ' ソケットオープン lngSck = socket(AF_INET, SOCK_DGRAM, 0) If lngSck = SOCKET_ERROR Then Exit Sub ' ソケット受信設定 Dim my_adr As SOCKADDR my_adr.sin_family = AF_INET my_adr.sin_port = htons(7777) my_adr.sin_addr = inet_addr("127.0.0.1") lngRtn = bind(lngSck, my_adr, Len(my_adr)) If lngRtn = SOCKET_ERROR Then closesocket lngSck WSACleanup Exit Sub End If ' 送信電文作成 Dim sdat() As Byte sdat = StrConv(Chr(2) & "1234あいう" & Chr(3), vbFromUnicode) ' ソケット送信 Dim to_adr As SOCKADDR to_adr.sin_family = AF_INET to_adr.sin_port = htons(8888) to_adr.sin_addr = inet_addr("127.0.0.1") lngRtn = sendto(lngSck, sdat(0), UBound(sdat) + 1, 0, to_adr, Len(to_adr)) If lngRtn = SOCKET_ERROR Then closesocket lngSck WSACleanup Exit Sub End If ' ソケット受信 Dim rdat(255) As Byte lngRtn = recv(lngSck, rdat(0), UBound(rdat) + 1, 0) If lngRtn = SOCKET_ERROR Then closesocket lngSck WSACleanup Exit Sub End If ' 受信電文表示 Debug.Print StrConv(rdat, vbUnicode) ' ソケットクローズ lngRtn = closesocket(lngSck) ' ソケット終了 lngRtn = WSACleanup() End Sub ' TCP/IPでの送信/受信(クライアント側) Private Sub Command2_Click() Dim lngRtn As Long Dim lngSck As Long ' ソケット初期化 Dim wsa_data As WSADATA lngRtn = WSAStartup(&H101, wsa_data) If lngRtn = SOCKET_ERROR Then Exit Sub ' ソケットオープン lngSck = socket(AF_INET, SOCK_STREAM, 0) If lngSck = SOCKET_ERROR Then Exit Sub ' ソケット接続 Dim to_adr As SOCKADDR to_adr.sin_family = AF_INET to_adr.sin_port = htons(8888) to_adr.sin_addr = inet_addr("127.0.0.1") lngRtn = connect(lngSck, to_adr, Len(to_adr)) If lngRtn = SOCKET_ERROR Then closesocket lngSck WSACleanup Exit Sub End If ' 送信電文作成 Dim sdat() As Byte sdat = StrConv(Chr(2) & "1234あいう" & Chr(3), vbFromUnicode) ' ソケット送信 lngRtn = send(lngSck, sdat(0), UBound(sdat) + 1, 0) If lngRtn = SOCKET_ERROR Then closesocket lngSck WSACleanup Exit Sub End If ' ソケット受信 Dim rdat(255) As Byte lngRtn = recv(lngSck, rdat(0), UBound(rdat) + 1, 0) If lngRtn = SOCKET_ERROR Then closesocket lngSck WSACleanup Exit Sub End If ' 受信電文表示 Debug.Print StrConv(rdat, vbUnicode) ' ソケットクローズ lngRtn = closesocket(lngSck) ' ソケット終了 lngRtn = WSACleanup() End Sub ' TCP/IPでの送信/受信(サーバー側) Private Sub Command3_Click() Dim lngRtn As Long ' ソケット初期化 Dim wsa_data As WSADATA lngRtn = WSAStartup(&H101, wsa_data) If lngRtn = SOCKET_ERROR Then Exit Sub ' ソケットオープン lngSck = socket(AF_INET, SOCK_STREAM, 0) If lngSck = SOCKET_ERROR Then Exit Sub ' ソケット接続設定 Dim my_adr As SOCKADDR my_adr.sin_family = AF_INET my_adr.sin_port = htons(8888) my_adr.sin_addr = INADDR_ANY lngRtn = bind(lngSck, my_adr, Len(my_adr)) If lngRtn = SOCKET_ERROR Then closesocket lngSck WSACleanup Exit Sub End If ' ソケット接続待ち lngRtn = listen(lngSck, 2) If lngRtn = SOCKET_ERROR Then closesocket lngSck WSACleanup Exit Sub End If ' FORMイベント(メッセージ)を処理する関数の登録 lngWnP = GetWindowLong(Text1.hWnd, GWL_WNDPROC) SetWindowLong Text1.hWnd, GWL_WNDPROC, AddressOf WndProc ' 接続要求があった時に発生するメッセージの登録 lngRtn = WSAAsyncSelect(lngSck, Text1.hWnd, 9999, FD_ACCEPT Or FD_READ Or FD_CLOSE) If lngRtn = SOCKET_ERROR Then closesocket lngSck WSACleanup Exit Sub End If End Sub ' TCP/IPでの送信/受信(サーバー側):TCP/IPクライアントからの接続有り Public Sub MyClientProc(ByVal wParam As Long, ByVal lParam As Long) Dim lngRtn As Long Select Case lParam Case FD_ACCEPT Debug.Print "Client Accept!!" ' ソケット接続許可 Dim from_adr As SOCKADDR Dim from_len As Long: from_len = Len(from_adr) lngCli = accept(lngSck, from_adr, from_len) If lngCli = SOCKET_ERROR Then Exit Sub End If ' 送信電文作成 Dim sdat() As Byte sdat = StrConv(Chr(2) & "1234あいう" & Chr(3), vbFromUnicode) ' ソケット送信 lngRtn = send(lngCli, sdat(0), UBound(sdat) + 1, 0) If lngRtn = SOCKET_ERROR Then closesocket lngCli Exit Sub End If Case FD_READ Debug.Print "Client Read!!" ' ソケット受信 Dim rdat(255) As Byte lngRtn = recv(lngCli, rdat(0), UBound(rdat) + 1, 0) If lngRtn = SOCKET_ERROR Then closesocket lngCli Exit Sub End If ' 受信電文表示 Debug.Print StrConv(rdat, vbUnicode) Case FD_CLOSE Debug.Print "Client Close!!" ' ソケットクローズ lngRtn = closesocket(lngCli) End Select End Sub ★標準モジュール(Module1.bas) Option Explicit ' ウィンドウのサブクラス化API Public Const GWL_WNDPROC = -4 Public Declare Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" _ (ByVal hWnd As Long, ByVal nIndex As Long) As Long Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" _ (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Public Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" _ (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal msg As Long, _ ByVal wParam As Long, ByVal lParam As Long) As Long ' ウィンドウ関数(デフォルト) Public lngWnP As Long ' TCP/IPでの送信/受信(サーバー側):ウィンドウ関数 Public Function WndProc( _ ByVal hWnd As Long, ByVal msg As Long, _ ByVal wParam As Long, ByVal lParam As Long) As Long WndProc = 0 Select Case msg Case 9999 ' クライアントからの要求があった時の処理 Form1.MyClientProc wParam, lParam Case Else ' デフォルトメッセージ処理 WndProc = CallWindowProc(lngWnP, hWnd, msg, wParam, lParam) End Select End Function |