Ошибка функции 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
Другие вопросы по тегам