Ошибка функции Winsock-bind в MASM(32 бит)
Прежде всего, я прошу прощения за мой плохой английский, английский не мой родной язык. Итак, я пытаюсь написать программу чата в Assembly 32 BIT, MASM.
Прямо сейчас я пишу код на стороне сервера. До сих пор я использовал функции WSAStartUp и Socket - Windows API, а сейчас я пытаюсь использовать функцию Bind.
Ссылка для функции привязки: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737550(v=vs.85).aspx
Это код, который я написал до сих пор (моя проблема написана после кода):
.386
.MODEL Flat, STDCALL
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\Ws2_32.inc
includelib \masm32\lib\Ws2_32.lib
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
.DATA
Success db 'WSAStartUp Succseed!',0
NO_Success db 'WSAStartUp NOT Succseed....',0
Socketsu db 'Socket :(:(:(:(',0
SocketSuccess db 'Socket Success!! :)',0
Bindno db 'Bind Error',0
Bindyes db 'Bind Success! :)',0
LocalIP db "127.0.0.1",0
port dd 8020
.DATA?
wsadata db 400 dup (?) ;WSADATA struct that hold the information about the Windows Sockets implementation.(info ret from WSATSTARTUP)
flag dw ?
ListenSocket dd ?
SockAddrStruct db 30 dup (?)
;so sockaddr_in <?>
sockaddrs db 16 dup (?)
.CONST
wVersionRequested equ 0101h
.CODE
main:
;-------------------WSAStartUp-----------------------;
;Initialize the work with winsock (WS StartUp = WINSOCK START UP)
invoke WSAStartup,wVersionRequested, offset wsadata
.if eax!=0
invoke MessageBoxA,NULL,offset NO_Success,offset NO_Success,MB_OK
jmp End_Program
.else
invoke MessageBoxA,NULL,offset Success,offset Success,MB_OK
.endif
;-------------------Socket-----------------------;
;AF_INET - address family(in format: host,port) to likboa the type of addresses that the socket can communicate with
invoke socket,AF_INET,SOCK_STREAM,IPPROTO_TCP
.IF eax==INVALID_SOCKET
invoke MessageBoxA,NULL,offset Socketsu,offset Socketsu,MB_OK
jmp End_Program
.else
invoke MessageBoxA,NULL,offset SocketSuccess,offset SocketSuccess,MB_OK
mov [ListenSocket],eax
.ENDIF
;-------------------Bind-------------------------;
;SockAddr Struct:
mov eax,AF_INET
mov [dword ptr sockaddrs],eax
invoke htons,[port]
mov [dword ptr sockaddrs+2],eax
invoke inet_addr,[dword ptr LocalIP]
mov [dword ptr sockaddrs+4],eax
invoke bind,SIZEOF sockaddrs,offset sockaddrs,ListenSocket
.if eax==0
invoke MessageBoxA,NULL,offset Bindyes,offset Bindyes,MB_OK
.else
invoke MessageBoxA,NULL,offset Bindno,offset Bindno,MB_OK
.endif
End_Program:
invoke ExitProcess,0
end main
Я не знаю в чем проблема. Но когда я запускаю код, я получаю созданный мной MessageBox, который гласит:Bind Error.
Я предполагаю, что это проблема в структуре sockaddrs (способ, которым я помещаю значения в него). Но я не знаю, что мне нужно изменить и как это исправить.
Я подумал, может быть, использовать функцию WSAGetLastError, чтобы увидеть, что такое ошибка, но я не знаю, как напечатать значение, которое возвращает функция, и посмотреть, что это за ошибка (я не могу вставить в invoke MessageBox, параметр EAX(регистр, который содержит возвращаемое значение)) .
Так может кто-нибудь помочь мне решить проблему в части "Связать"?
Большое спасибо!
1 ответ
WSAGetLastError
У вас есть пара вопросов. Я начну с того, что дам вам один метод получения сообщения, представляющего последний WSAGetLastError
(это также работает с GetLastError
). Win32 API способ заключается в использовании FormatMessage
преобразовать код сообщения об ошибке, возвращенный WSAGetLastError
, Информацию из MSDN о FormatMessage можно найти здесь, а также пример, подобный коду, который мы будем использовать. Он определяется как:
DWORD WINAPI FormatMessage (
В DWORD dwFlags,
In_opt LPCVOID lpSource,
В DWORD dwMessageId,
В DWORD dwLanguageId,
Out LPTSTR lpBuffer,
В DWORD nSize,
In_opt va_list * Аргументы
);
В вашем .DATA?
область, добавьте переменную для хранения указателя буфера, из которого мы вернемся FormatMessage
:
lpErrorMsg dd ?
Чтобы затем извлечь и отобразить последнюю ошибку WSA, вы можете использовать что-то вроде этого после вызова, связанного с сокетом (например, bind
):
.if eax==SOCKET_ERROR
invoke WSAGetLastError
invoke FormatMessageA, FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, eax, LANG_NEUTRAL, offset lpErrorMsg, 0, NULL
invoke MessageBoxA,NULL,lpErrorMsg,offset Bindno,MB_OK
.endif
Исправление ошибок
В вашем коде есть ряд проблем. Первое, что я заметил, было то, что port
должно быть 32-битным целым числом, поэтому оно должно быть определено как:
port dd 8020
Без этого изменения htons
не будет работать должным образом, так как ожидается 32-разрядное целое число.
Следующая ошибка здесь:
invoke MessageBoxA,NULL,offset SocketSuccess,offset SocketSuccess,MB_OK
mov [ListenSocket],eax
Ты бьешь eax
позвонив MessageBoxA
первый. Вы, вероятно, хотели сначала сохранить его:
mov [ListenSocket],eax
invoke MessageBoxA,NULL,offset SocketSuccess,offset SocketSuccess,MB_OK
Кажется, в этом коде есть ряд проблем:
mov eax,AF_INET
mov [dword ptr sockaddrs],eax
Это неверно, так как работает с 32-разрядным целым числом, и нам нужно WORD(16-разрядное). Так должно быть:
mov ax,AF_INET
mov [word ptr sockaddrs],ax
Это также требует использования 16-битного СЛОВА для хранения в sockaddrs+2
:
invoke htons,[port]
mov [dword ptr sockaddrs+2],eax
Так должно было быть:
invoke htons,[port]
mov [word ptr sockaddrs+2],ax
Это неверно, так как мы не хотим отменять ссылки на то, что находится в LocalIP, мы просто хотим адрес LocalIP:
invoke inet_addr,[dword ptr LocalIP]
mov [dword ptr sockaddrs+4],eax
Так что это кажется более правильным:
invoke inet_addr, offset LocalIP
mov [dword ptr sockaddrs+4],eax
Затем вы перепутали параметры bind
, Ты имел:
invoke bind,SIZEOF sockaddrs,offset sockaddrs,ListenSocket
Это должно было быть:
invoke bind,ListenSocket,offset sockaddrs,SIZEOF sockaddrs
Более простой способ работы с sockaddr_in
MASM32 определяет sockaddr_in
со всеми полями определены. Чтобы упростить работу с этой структурой и сделать код более читабельным, вы можете рассмотреть возможность изменения SockAddrStruct
определяется как (и обнуляется):
SockAddrStruct sockaddr_in <0>
С SockAddrStruct
Определившись таким образом, теперь вы можете изменить свой код сокета, чтобы прочитать что-то вроде этого:
;-------------------Bind-------------------------;
;SockAddr Struct:
mov SockAddrStruct.sin_family,AF_INET
invoke htons, [port]
mov SockAddrStruct.sin_port,ax
invoke inet_addr, offset LocalIP
mov SockAddrStruct.sin_addr.S_un.S_addr, eax
invoke bind,ListenSocket,offset SockAddrStruct,SIZEOF SockAddrStruct