Обещанный пример, сервер:
;объявление констант
AF_INET := 2
SOCK_STREAM := 1
IPPROTO_TCP := 6
WSA_FLAG_OVERLAPPED := 1
WM_USER := 0x400
WM_SOCKET := WM_USER + 1
FD_READ := 0x01
FD_WRITE := 0x02
FD_OOB := 0x04
FD_ACCEPT := 0x08
FD_CONNECT := 0x10
FD_CLOSE := 0x20
;объявление переменных
VarSetCapacity(WSAData, 108, 0) ;для x86 хватит и 100
Socket := -1
AcceptSocket := -1
VarSetCapacity(SockAddr, 16, 0)
VarSetCapacity(buf, 1024, 0)
;код
Gui, Add, ListView, w480 h240, сокет|сообщение
Gui, Show
Gui, +LastFound
hWnd := WinExist()
OnMessage(WM_SOCKET, "DlgProc", 5)
DllCall("LoadLibrary", "str", "Ws2_32.dll")
if(DllCall("Ws2_32.dll\WSAStartup", "ushort", 0x0202, "ptr", &WSAData))
{
msgbox WSAStartup
goto Clear
}
Socket := DllCall("Ws2_32.dll\socket", "int", AF_INET, "int", SOCK_STREAM, "int", IPPROTO_TCP, "ptr")
if(Socket=-1)
{
msgbox Socket
goto Clear
}
NumPut(AF_INET, &SockAddr, 0, "short")
NumPut(htons(5676), &SockAddr, 2, "ushort")
NumPut(inet_addr("127.0.0.1"), &SockAddr, 4, "uint")
if(DllCall("Ws2_32.dll\WSAAsyncSelect", "ptr", Socket, "ptr", hWnd, "uint", WM_SOCKET, "int", FD_ACCEPT|FD_CLOSE, "int")=-1)
{
msgbox % "WSAAsyncSelect " . DllCall("Ws2_32.dll\WSAGetLastError")
goto Clear
}
if(DllCall("Ws2_32.dll\bind", "ptr", Socket, "ptr", &SockAddr, "int", 16, "int")=-1)
{
msgbox % "bind " . DllCall("Ws2_32.dll\WSAGetLastError")
goto Clear
}
if(DllCall("Ws2_32.dll\listen", "ptr", Socket, "int", 5, "int")=-1)
{
msgbox % "listen " . DllCall("Ws2_32.dll\WSAGetLastError")
goto Clear
}
return
Clear:
if(Socket)
DllCall("Ws2_32.dll\closesocket", "ptr", Socket)
DllCall("Ws2_32.dll\WSACleanup")
return
DlgProc(wParam, lParam, msg, hwnd)
{
global
local fd, ClientSocket, r
if(msg=WM_SOCKET)
{
fd := lParam&0xFFFF
if(fd=FD_ACCEPT)
{
LV_Add("", wParam, "FD_ACCEPT")
ClientSocket := DllCall("Ws2_32.dll\accept", "ptr", wParam, "ptr", 0, "int", 0, "ptr")
DllCall("Ws2_32.dll\WSAAsyncSelect", "ptr", ClientSocket, "ptr", hWnd, "uint", WM_SOCKET, "int", FD_READ|FD_WRITE|FD_CLOSE, "int")
}
else if(fd=FD_READ)
{
LV_Add("", wParam, "FD_READ")
x:=DllCall("Ws2_32.dll\recv", "ptr", wParam, "ptr", &buf, "int", 1024, "int", 0)
LV_Add("", wParam, StrGet(&buf, x, "utf-16"))
}
else if(fd=FD_WRITE)
{
LV_Add("", wParam, "FD_WRITE")
}
else if(fd=FD_CLOSE)
{
LV_Add("", wParam, "FD_CLOSE")
DllCall("Ws2_32.dll\closesocket", "ptr", wParam)
}
else
{
LV_Add("", wParam, "???")
}
}
}
inet_addr(StringWithIP)
{
ret := RegExMatch(StringWithIP, "^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$", ArrayWithIP)
if((ret="")||(ret=0))
return ""
if((ArrayWithIP1>127)||(ArrayWithIP2>127)||(ArrayWithIP3>127)||(ArrayWithIP4>127))
return ""
VarSetCapacity(ip, 4, 0)
NumPut(ArrayWithIP1, &ip, 0, "uchar")
NumPut(ArrayWithIP2, &ip, 1, "uchar")
NumPut(ArrayWithIP3, &ip, 2, "uchar")
NumPut(ArrayWithIP4, &ip, 3, "uchar")
return NumGet(&ip, 0, "uint")
}
htons(port)
{
if((port<0)||(port>0xFFFF))
return ""
return ((port&0xFF)<<8)|(port>>8)
}
GuiClose:
ExitApp
Клиент:
AF_INET := 2
SOCK_STREAM := 1
IPPROTO_TCP := 6
WSA_FLAG_OVERLAPPED := 1
WM_USER := 0x400
WM_SOCKET := WM_USER + 1
FD_READ := 0x01
FD_WRITE := 0x02
FD_OOB := 0x04
FD_ACCEPT := 0x08
FD_CONNECT := 0x10
FD_CLOSE := 0x20
WSAEWOULDBLOCK := 10035
;объявление переменных
VarSetCapacity(WSAData, 108, 0) ;для x86 хватит и 100
Socket := -1
AcceptSocket := -1
VarSetCapacity(SockAddr, 16, 0)
VarSetCapacity(buf, 1024, 0)
;код
Gui, Add, ListView, w480 h240, сокет|сообщение
Gui, Add, Button, default, Ping1
Gui, Add, Button, default, Ping2
Gui, Show
Gui, +LastFound
hWnd := WinExist()
OnMessage(WM_SOCKET, "DlgProc", 5)
DllCall("LoadLibrary", "str", "Ws2_32.dll")
if(DllCall("Ws2_32.dll\WSAStartup", "ushort", 0x0202, "ptr", &WSAData))
{
msgbox WSAStartup
goto Clear
}
Socket := DllCall("Ws2_32.dll\socket", "int", AF_INET, "int", SOCK_STREAM, "int", IPPROTO_TCP, "ptr")
if(Socket=-1)
{
msgbox Socket
goto Clear
}
if(DllCall("Ws2_32.dll\WSAAsyncSelect", "ptr", Socket, "ptr", hWnd, "uint", WM_SOCKET, "int", FD_READ|FD_WRITE|FD_CLOSE, "int")=-1)
{
msgbox % "WSAAsyncSelect " . DllCall("Ws2_32.dll\WSAGetLastError")
goto Clear
}
NumPut(AF_INET, &SockAddr, 0, "short")
NumPut(htons(5676), &SockAddr, 2, "ushort")
NumPut(inet_addr("127.0.0.1"), &SockAddr, 4, "uint")
if(DllCall("Ws2_32.dll\connect", "ptr", Socket, "ptr", &SockAddr, "int", 16)=-1)
{
if(DllCall("Ws2_32.dll\WSAGetLastError")!=WSAEWOULDBLOCK)
{
msgbox connect
goto Clear
}
}
return
Clear:
if(Socket)
DllCall("Ws2_32.dll\closesocket", "ptr", Socket)
DllCall("Ws2_32.dll\WSACleanup")
return
DlgProc(wParam, lParam, msg, hwnd)
{
global
local fd
if(msg=WM_SOCKET)
{
fd := lParam&0xFFFF
if(fd=FD_READ)
{
LV_Add("", wParam, "FD_READ")
}
else if(fd=FD_WRITE)
{
LV_Add("", wParam, "FD_WRITE")
}
else if(fd=FD_CLOSE)
{
LV_Add("", wParam, "FD_CLOSE")
DllCall("Ws2_32.dll\closesocket", "ptr", wParam)
}
else
{
LV_Add("", wParam, "???")
}
}
}
inet_addr(StringWithIP)
{
ret := RegExMatch(StringWithIP, "^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$", ArrayWithIP)
if((ret="")||(ret=0))
return ""
if((ArrayWithIP1>255)||(ArrayWithIP2>255)||(ArrayWithIP3>255)||(ArrayWithIP4>255))
return ""
VarSetCapacity(ip, 4, 0)
NumPut(ArrayWithIP1, &ip, 0, "uchar")
NumPut(ArrayWithIP2, &ip, 1, "uchar")
NumPut(ArrayWithIP3, &ip, 2, "uchar")
NumPut(ArrayWithIP4, &ip, 3, "uchar")
return NumGet(&ip, 0, "uint")
}
htons(port)
{
if((port<0)||(port>0xFFFF))
return ""
return ((port&0xFF)<<8)|(port>>8)
}
ButtonPing1:
StrPut("pg|1", &buf, 8, "utf-16")
DllCall("Ws2_32.dll\send", "ptr", Socket, "ptr", &buf, "int", 16, "int", 0)
return
ButtonPing2:
StrPut("pg|2", &buf, 8, "utf-16")
DllCall("Ws2_32.dll\send", "ptr", Socket, "ptr", &buf, "int", 16, "int", 0)
return
GuiClose:
ExitApp
Очень много кода совпадает, поэтому можно вынести его в отдельный файл. htons и inet_addr аналоги стандартных функций- первая преобразует порт(меняет байты местами), а вторая преобразует строку с ip-адресом в число(двойное слово, uint).
Ещё стоит обратить внимание на то, что в используемом режиме функция "connect" почти всегда возвращает ошибку с кодом WSAEWOULDBLOCK, поэтому нельзя сразу точно сказать установлена связь или нет. Если установлена, то придёт сообщение FD_WRITE(т.е. можно писАть). Как только сервер получает данные, приходит сообщение FD_WRITE, FD_CLOSE приходит если кто-то закрыл соединение.
Тут довольно много кода, поэтому всё я описывать не буду, лучше отвечу на вопросы, если таковые найдутся.
Кстати можно посмотреть книгу "Программирование в сетях Microsoft Windows"(легко найти в сети), там в 8-ой главе есть описание моделей ввода-вывода, в том числе и этой.