Introduction

API Winsock

Exemple
Ecrivez-moi

En partenariat avec amazon.fr

CLIENT-SERVEUR

 

Pour utiliser l'exemple, il faut créer un nouveau projet sous VB et rajouter les fichiers suivants :

ClientServeur.frm

WinsockDefs.bas

Subclass.bas

J'utilise une fonction CALLBACK pour intercepter les messages Windows. Or l'interface VB n'aime pas trop cela. Donc il faut utiliser l'executable pour tester ce programme.

Si vous etes en mono-poste, lancez deux fois le programme, vous en mettez un en serveur et vous connectez le client dessus.

Je précise qu'il s'agit juste d'un exemple pour comprendre le concept général : cette version ne gère qu'un seul client.

Pour toutes questions : webmaster@vbenreseau.com

 

ClientServeur.frm


Option Explicit
Private LocalServer As SOCK_ADDR
Private rmtserver As SOCK_ADDR
Private Sub Client_Click()

Dim wsadata As WSA_DATA
Dim sock As Long
Dim CR As Long

Form1.Caption = "Client"
CR = WSAStartup(&H101, wsadata)
If CR <> 0 Then
MsgBox "Mauvaise version de Winsock.dll"
Exit Sub
End If

sock = Socket(AF_INET, SOCK_STREAM, 0)
If sock < 0 Then
MsgBox "Erreur sur la creation du socket = " & WSAGetLastError()
Exit Sub
End If

List1.AddItem sock & " : Client"

rmtserver.sin_family = AF_INET
rmtserver.sin_port = htons(Port.Text)
rmtserver.sin_addr.S_addr = inet_addr(IP.Text)
rmtserver.sin_zero(0) = 0
CR = connect(sock, rmtserver, Len(rmtserver))
If CR < 0 Then
MsgBox "Erreur sur Connect : " & WSAGetLastError()
FermerSocket sock
Exit Sub
End If

CR = WSAAsyncSelect(sock, Form1.hwnd, WM_USER + 1, FD_READ Or FD_CLOSE)
If CR < 0 Then
MsgBox "Erreur sur WSAAsyncSelect = " & WSAGetLastError()
FermerSocket sock
Exit Sub
End If

End Sub
Private Sub Emission_KeyPress(KeyAscii As Integer)

Dim i As Integer
Dim sock As Long
Dim message As String

If KeyAscii = vbKeyReturn Then
message = Emission.Text
For i = 0 To List1.ListCount - 1
sock = Left(Form1.List1.List(i), InStr(1, Form1.List1.List(i), " ") - 1)
message = sock & ":>" & Emission.Text
Reception.Text = message & vbCrLf & Reception.Text
Envoyer sock, message
Next

Emission.Text = ""
End If

End Sub
Private Sub Form_Load()

Call SetHook(hwnd, True)
IP.Text = "127.0.0.1"
Port.Text = 2000

End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)

Call SetHook(hwnd, False)

End Sub
Private Sub Fin_Click()

Dim i As Integer
Dim sock As Long

For i = 1 To List1.ListCount - 1
sock = Left(Form1.List1.List(i), InStr(1, Form1.List1.List(i), " ") - 1)
FermerSocket sock
Next

Serveur.Enabled = True

End Sub
Private Sub Serveur_Click()

Dim CR As Long
Dim wsadata As WSA_DATA
Dim sock As Long


Form1.Caption = "Serveur"
CR = WSAStartup(&H101, wsadata)
If CR <> 0 Then
MsgBox "Mauvaise version de Winsock.dll"
Exit Sub
End If

sock = Socket(AF_INET, SOCK_STREAM, 0)
If sock < 0 Then
MsgBox "Erreur sur la creation du socket = " & WSAGetLastError()
Exit Sub
End If

LocalServer.sin_family = AF_INET
LocalServer.sin_port = htons(Port.Text)
LocalServer.sin_addr.S_addr = INADDR_ANY
LocalServer.sin_zero(0) = 0
CR = bind(sock, LocalServer, Len(LocalServer))
If CR < 0 Then
MsgBox "Erreur sur bind : " & WSAGetLastError()
FermerSocket sock
Exit Sub
End If

CR = listen(sock, 2)
If CR < 0 Then
MsgBox "Erreur sur listen : " & WSAGetLastError()
FermerSocket sock
Exit Sub
End If

CR = WSAAsyncSelect(sock, Form1.hwnd, WM_USER + 1, FD_READ Or FD_CLOSE Or FD_ACCEPT)
If CR < 0 Then
MsgBox "Erreur sur WSAAsyncSelect = " & WSAGetLastError()
FermerSocket sock
Exit Sub
End If

Serveur.Enabled = False

End Sub
Public Function VbAccept(ByVal hwnd As Long, ByVal msg As Long, _
ByVal wParam As Long, ByVal lParam As Long)

Dim AdrIP As String
Dim message As String
Dim sock As Long

AdrIP = ""
sock = Accepter(wParam, rmtserver, AdrIP)

List1.AddItem sock & " : " & AdrIP

message = "Connection etablie"
Envoyer sock, message

End Function
Function VbClose(ByVal hwnd As Long, ByVal msg As Long, _
ByVal wParam As Long, ByVal lParam As Long)

Dim i As Long

For i = 0 To List1.ListCount - 1
If Left(List1.List(i), InStr(1, List1.List(i), " ") - 1) = wParam Then
List1.RemoveItem i
Exit For
End If
Next

End Function
Public Function VbRecv(ByVal hwnd As Long, ByVal msg As Long, _
ByVal
wParam As Long, ByVal lParam As Long)

Dim message As String
Dim sock As Long
Dim i As Long

message = Recevoir(wParam)
Reception.Text = message & vbCrLf & Reception.Text

If List1.ListCount > 1 Then
For i = 0 To List1.ListCount - 1
sock = Left(List1.List(i), InStr(1, List1.List(i), " ") - 1)
Envoyer sock, message
Next
End If

End Function

 

WinsockDefs.bas

Option Explicit

Public Const WSANOERROR = 0

'Address families.

Public Const AF_UNSPEC = 0
Public Const AF_UNIX = 1
Public Const AF_INET = 2
Public Const AF_IMPLINK = 3
Public Const AF_PUP = 4
Public Const AF_CHAOS = 5
Public Const AF_IPX = 6
Public Const AF_NS = 6
Public Const AF_ISO = 7
Public Const AF_OSI = AF_ISO
Public Const AF_ECMA = 8
Public Const AF_DATAKIT = 9
Public Const AF_CCITT = 10
Public Const AF_SNA = 11
Public Const AF_DECnet = 12
Public Const AF_DLI = 13
Public Const AF_LAT = 14
Public Const AF_HYLINK = 15
Public Const AF_APPLETALK = 16
Public Const AF_NETBIOS = 17
Public Const AF_VOICEVIEW = 18
Public Const AF_FIREFOX = 19
Public Const AF_UNKNOWN1 = 20
Public Const AF_BAN = 21
Public Const AF_MAX = 22

Public Const PF_UNSPEC = AF_UNSPEC
Public Const PF_UNIX = AF_UNIX
Public Const PF_INET = AF_INET
Public Const PF_IMPLINK = AF_IMPLINK
Public Const PF_PUP = AF_PUP
Public Const PF_CHAOS = AF_CHAOS
Public Const PF_NS = AF_NS
Public Const PF_IPX = AF_IPX
Public Const PF_ISO = AF_ISO
Public Const PF_OSI = AF_OSI
Public Const PF_ECMA = AF_ECMA
Public Const PF_DATAKIT = AF_DATAKIT
Public Const PF_CCITT = AF_CCITT
Public Const PF_SNA = AF_SNA
Public Const PF_DECnet = AF_DECnet
Public Const PF_DLI = AF_DLI
Public Const PF_LAT = AF_LAT
Public Const PF_HYLINK = AF_HYLINK
Public Const PF_APPLETALK = AF_APPLETALK
Public Const PF_VOICEVIEW = AF_VOICEVIEW
Public Const PF_FIREFOX = AF_FIREFOX
Public Const PF_UNKNOWN1 = AF_UNKNOWN1
Public Const PF_BAN = AF_BAN
Public Const PF_MAX = AF_MAX


'Public Const AF_INET = 2
'Public Const PF_INET = AF_INET
Public Const IPPROTO_IP = 0
Public Const IPPROTO_ICMP = 1
Public Const IPPROTO_IGMP = 2
Public Const IPPROTO_GGP = 3
Public Const IPPROTO_TCP = 6
Public Const IPPROTO_PUP = 12
Public Const IPPROTO_UDP = 17
Public Const IPPROTO_IDP = 22
Public Const IPPROTO_ND = 77

'/*
' * bit values and indices for FD_XXX network events
' */
Public Const FD_READ = &H1
Public Const FD_WRITE = &H2
Public Const FD_OOB = &H4
Public Const FD_ACCEPT = &H8
Public Const FD_CONNECT = &H10
Public Const FD_CLOSE = &H20


'Define socket types
Public Const SOCK_STREAM = 1 'Stream socket
Public Const SOCK_DGRAM = 2 'Datagram socket
Public Const SOCK_RAW = 3 'Raw data socket
Public Const SOCK_RDM = 4 'Reliable Delivery socket
Public Const SOCK_SEQPACKET = 5 'Sequenced Packet socket

Public Const INADDR_ANY = &H0
Public Const INADDR_LOOPBACK = &H7F000001
Public Const INADDR_BROADCAST = &HFFFF
Public Const INADDR_NONE = &HFFFF


'Public Const SOCK_STREAM = 1&
Public Const WSADESCRIPTION_LEN = 256
Public Const WSASYS_STATUS_LEN = 128

Public Const INVALID_SOCKET = -1&
Public Const SOCKET_ERROR = -1&
'Public Const INADDR_NONE = &HFFFFFFFF

' All Windows Sockets error constants are biased by WSABASEERR from the "normal"

Public Const WSABASEERR = 10000

' Windows Sockets definitions of regular Microsoft C error constants

Public Const WSAEINTR = (WSABASEERR + 4)
Public Const WSAEBADF = (WSABASEERR + 9)
Public Const WSAEACCES = (WSABASEERR + 13)
Public Const WSAEFAULT = (WSABASEERR + 14)
Public Const WSAEINVAL = (WSABASEERR + 22)
Public Const WSAEMFILE = (WSABASEERR + 24)

' Windows Sockets definitions of regular Berkeley error constants

Public Const WSAEWOULDBLOCK = (WSABASEERR + 35)
Public Const WSAEINPROGRESS = (WSABASEERR + 36)
Public Const WSAEALREADY = (WSABASEERR + 37)
Public Const WSAENOTSOCK = (WSABASEERR + 38)
Public Const WSAEDESTADDRREQ = (WSABASEERR + 39)
Public Const WSAEMSGSIZE = (WSABASEERR + 40)
Public Const WSAEPROTOTYPE = (WSABASEERR + 41)
Public Const WSAENOPROTOOPT = (WSABASEERR + 42)
Public Const WSAEPROTONOSUPPORT = (WSABASEERR + 43)
Public Const WSAESOCKTNOSUPPORT = (WSABASEERR + 44)
Public Const WSAEOPNOTSUPP = (WSABASEERR + 45)
Public Const WSAEPFNOSUPPORT = (WSABASEERR + 46)
Public Const WSAEAFNOSUPPORT = (WSABASEERR + 47)
Public Const WSAEADDRINUSE = (WSABASEERR + 48)
Public Const WSAEADDRNOTAVAIL = (WSABASEERR + 49)
Public Const WSAENETDOWN = (WSABASEERR + 50)
Public Const WSAENETUNREACH = (WSABASEERR + 51)
Public Const WSAENETRESET = (WSABASEERR + 52)
Public Const WSAECONNABORTED = (WSABASEERR + 53)
Public Const WSAECONNRESET = (WSABASEERR + 54)
Public Const WSAENOBUFS = (WSABASEERR + 55)
Public Const WSAEISCONN = (WSABASEERR + 56)
Public Const WSAENOTCONN = (WSABASEERR + 57)
Public Const WSAESHUTDOWN = (WSABASEERR + 58)
Public Const WSAETOOMANYREFS = (WSABASEERR + 59)
Public Const WSAETIMEDOUT = (WSABASEERR + 60)
Public Const WSAECONNREFUSED = (WSABASEERR + 61)
Public Const WSAELOOP = (WSABASEERR + 62)
Public Const WSAENAMETOOLONG = (WSABASEERR + 63)
Public Const WSAEHOSTDOWN = (WSABASEERR + 64)
Public Const WSAEHOSTUNREACH = (WSABASEERR + 65)
Public Const WSAENOTEMPTY = (WSABASEERR + 66)
Public Const WSAEPROCLIM = (WSABASEERR + 67)
Public Const WSAEUSERS = (WSABASEERR + 68)
Public Const WSAEDQUOT = (WSABASEERR + 69)
Public Const WSAESTALE = (WSABASEERR + 70)
Public Const WSAEREMOTE = (WSABASEERR + 71)

Public Const WSAEDISCON = (WSABASEERR + 101)

' Extended Windows Sockets error constant definitions

Public Const WSASYSNOTREADY = (WSABASEERR + 91)
Public Const WSAVERNOTSUPPORTED = (WSABASEERR + 92)
Public Const WSANOTINITIALISED = (WSABASEERR + 93)

' Error return codes from gethostbyname() and gethostbyaddr()
' (when using the resolver). Note that these errors are
' retrieved via WSAGetLastError() and must therefore follow
' the rules for avoiding clashes with error numbers from
' specific implementations or language run-time systems.
' For this reason the codes are based at WSABASEERR+1001.
' Note also that [WSA]NO_ADDRESS is defined only for
' compatibility purposes.

' Authoritative Answer: Host not found

Public Const WSAHOST_NOT_FOUND = (WSABASEERR + 1001)
Public Const HOST_NOT_FOUND = WSAHOST_NOT_FOUND

' Non-Authoritative: Host not found, or SERVERFAIL

Public Const WSATRY_AGAIN = (WSABASEERR + 1002)
Public Const TRY_AGAIN = WSATRY_AGAIN

' Non recoverable errors, FORMERR, REFUSED, NOTIMP

Public Const WSANO_RECOVERY = (WSABASEERR + 1003)
Public Const NO_RECOVERY = WSANO_RECOVERY

' Valid name, no data record of requested type

Public Const WSANO_DATA = (WSABASEERR + 1004)
Public Const NO_DATA = WSANO_DATA

' no address, look for MX record

Public Const WSANO_ADDRESS = WSANO_DATA
Public Const NO_ADDRESS = WSANO_ADDRESS

' Windows Sockets errors redefined as regular Berkeley error constants.
' These are commented out in Windows NT to avoid conflicts with errno.h.
' Use the WSA constants instead.

Public Const EWOULDBLOCK = WSAEWOULDBLOCK
Public Const EINPROGRESS = WSAEINPROGRESS
Public Const EALREADY = WSAEALREADY
Public Const ENOTSOCK = WSAENOTSOCK
Public Const EDESTADDRREQ = WSAEDESTADDRREQ
Public Const EMSGSIZE = WSAEMSGSIZE
Public Const EPROTOTYPE = WSAEPROTOTYPE
Public Const ENOPROTOOPT = WSAENOPROTOOPT
Public Const EPROTONOSUPPORT = WSAEPROTONOSUPPORT
Public Const ESOCKTNOSUPPORT = WSAESOCKTNOSUPPORT
Public Const EOPNOTSUPP = WSAEOPNOTSUPP
Public Const EPFNOSUPPORT = WSAEPFNOSUPPORT
Public Const EAFNOSUPPORT = WSAEAFNOSUPPORT
Public Const EADDRINUSE = WSAEADDRINUSE
Public Const EADDRNOTAVAIL = WSAEADDRNOTAVAIL
Public Const ENETDOWN = WSAENETDOWN
Public Const ENETUNREACH = WSAENETUNREACH
Public Const ENETRESET = WSAENETRESET
Public Const ECONNABORTED = WSAECONNABORTED
Public Const ECONNRESET = WSAECONNRESET
Public Const ENOBUFS = WSAENOBUFS
Public Const EISCONN = WSAEISCONN
Public Const ENOTCONN = WSAENOTCONN
Public Const ESHUTDOWN = WSAESHUTDOWN
Public Const ETOOMANYREFS = WSAETOOMANYREFS
Public Const ETIMEDOUT = WSAETIMEDOUT
Public Const ECONNREFUSED = WSAECONNREFUSED
Public Const ELOOP = WSAELOOP
Public Const ENAMETOOLONG = WSAENAMETOOLONG
Public Const EHOSTDOWN = WSAEHOSTDOWN
Public Const EHOSTUNREACH = WSAEHOSTUNREACH
Public Const ENOTEMPTY = WSAENOTEMPTY
Public Const EPROCLIM = WSAEPROCLIM
Public Const EUSERS = WSAEUSERS
Public Const EDQUOT = WSAEDQUOT
Public Const ESTALE = WSAESTALE
Public Const EREMOTE = WSAEREMOTE

Type WSA_DATA
wVersion As Integer
wHighVersion As Integer
strDescription(WSADESCRIPTION_LEN + 1) As Byte
strSystemStatus(WSASYS_STATUS_LEN + 1) As Byte
iMaxSockets As Integer
iMaxUdpDg As Integer
lpVendorInfo As Long
End Type

Type IN_ADDR
S_addr As Long
End Type

Type SOCK_ADDR
sin_family As Integer
sin_port As Integer
sin_addr As IN_ADDR
sin_zero(0 To 7) As Byte
End Type

Type Inet_Adress
Byte4 As String * 1
Byte3 As String * 1
Byte2 As String * 1
Byte1 As String * 1
End Type

Public Const FD_SETSIZE = 64
Type FD_SET
fd_count As Long
fd_array(0 To FD_SETSIZE - 1) As Long
End Type

Type TIME_VAL
tv_sec As Long
tv_usec As Long
End Type

Declare Function bind Lib "wsock32" _
(ByVal s As Long, Addr As SOCK_ADDR, ByVal namelen As Long) As Long
Declare Function closesocket Lib "wsock32" _
(ByVal s As Long) As Long
Declare Function connect Lib "wsock32" _
(ByVal s As Long, name As SOCK_ADDR, ByVal namelen As Integer) As Long
Declare Function inet_addr Lib "wsock32" _
(ByVal cp As String) As Long
Declare Function htons Lib "wsock32" _
(ByVal hostshort As Integer) As Integer
Declare Function recv Lib "wsock32" _
(ByVal s As Long, buffer As Any, ByVal length As Long, ByVal flags As Long) As Long
Declare Function send Lib "wsock32" _
(ByVal s As Long, buffer As Any, ByVal length As Long, ByVal flags As Long) As Long
Declare Function shutdown Lib "wsock32" (ByVal s As Long, ByVal how As Long) As Long
Declare Function sselect Lib "wsock32" Alias "select" _
(ByVal nfds As Long, readfds As FD_SET, writefds As FD_SET,_
exceptfds As FD_SET, timeout As TIME_VAL) As Long
Declare Function Socket Lib "wsock32" Alias "socket" _
(ByVal af As Long, ByVal type_specification As Long, ByVal protocol As Long) As Long
Declare Function WSACancelBlockingCall Lib "wsock32" () As Long
Declare Function WSACleanUp Lib "wsock32" Alias "WSACleanup" () As Long
Declare Function WSAGetLastError Lib "wsock32" () As Long
Declare Function WSAStartup Lib "wsock32" _
(ByVal wVersionRequired As Integer, wsData As WSA_DATA) As Long

Declare Function WSAAsyncSelect Lib "wsock32.dll" _
(ByVal s As Long, ByVal hwnd As Long, _
ByVal
wMsg As Integer, ByVal lEvent As Long) As Integer

Declare Function listen Lib "wsock32.dll" _
(ByVal s As Long, ByVal backlog As Integer) As Integer

Declare Function accept Lib "wsock32.dll" _
(ByVal sock As Long, ByRef Addr As SOCK_ADDR, ByRef namelen As Integer) As Long
Declare Function inet_ntoa Lib "wsock32.dll" (ByVal inet As Long) As Long

Public
Sub FermerSocket(sock As Long)

Dim lngResult As Long

If sock <> 0 Then
lngResult = shutdown(sock, 2)
lngResult = closesocket(sock)
End If
lngResult = WSACancelBlockingCall
lngResult = WSACleanUp
sock = 0

End Sub
Public Function Accepter(sock As Long, rmtserver As SOCK_ADDR, AdrIP As String) As Long

Dim IPStruct As Inet_Adress

Accepter = accept(sock, rmtserver, Len(rmtserver))

CopyMemory IPStruct, rmtserver.sin_addr.S_addr, 4
AdrIP = CStr(Asc(IPStruct.Byte4)) & "." & _
CStr
(Asc(IPStruct.Byte3)) & "." & _
CStr
(Asc(IPStruct.Byte2)) & "." & _
CStr
(Asc(IPStruct.Byte1))

End Function
Public Function Recevoir(sock As Long) As String

Dim CR As Long
Const MAX_BUFF_SIZE = 10000
Dim buff(0 To MAX_BUFF_SIZE) As Byte

CR = recv(sock, buff(0), MAX_BUFF_SIZE, 0)

If CR < 0 Then
MsgBox "Erreur sur recv = " & WSAGetLastError()
FermerSocket sock
Exit Function
End If
buff(CR) = 0

Recevoir = Left(StrConv(buff(), vbUnicode), CR)

End Function
Public Sub Envoyer(sock As Long, message As String)

Dim CR As Long

CR = send(sock, ByVal message, Len(message), 0)
If CR < 0 Then
MsgBox "Erreur sur l'envoi du message = " & WSAGetLastError()
FermerSocket sock
Exit Sub
End If

End Sub

 

Subclass.bas


Option Explicit

Public Const WM_USER = &H400

Public Const GWL_WNDPROC = (-4)
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)

Public origWndProc As Long
Public Sub SetHook(hwnd, bSet As Boolean)

If bSet Then
origWndProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf AppWndProc)
ElseIf origWndProc Then
Dim lRet As Long
lRet = SetWindowLong(hwnd, GWL_WNDPROC, origWndProc)
End If

End Sub
Public Function AppWndProc(ByVal hwnd As Long, ByVal msg As Long, _
ByVal
wParam As Long, ByVal lParam As Long) As Long

Select Case msg
Case WM_USER + 1
Select Case LoWord(lParam)
Case FD_READ
Form1.VbRecv hwnd, msg, wParam, lParam
Case FD_CLOSE
Form1.VbClose hwnd, msg, wParam, lParam
Case FD_ACCEPT
Form1.VbAccept hwnd, msg, wParam, lParam
End Select
End Select
AppWndProc = CallWindowProc(origWndProc, hwnd, msg, wParam, lParam)

End Function
Public Function LoWord(ByVal LongIn As Long) As Integer

Call CopyMemory(LoWord, LongIn, 2)

End Function
Public Function HiWord(ByVal LongIn As Long) As Integer

Call CopyMemory(HiWord, ByVal (VarPtr(LongIn) + 2), 2)

End Function