MASM(32 位 asm)中的 Winsock 绑定函数错误

Winsock-bind function error In MASM(32 BIT asm)

首先,我很抱歉我的英语不好,英语不是我的第一语言。 所以,我正在尝试用 32 位汇编语言编写聊天程序,MASM。

现在,我正在编写服务器端代码,到目前为止我使用了 WSAStartUp 和 Socket - Windows API 函数,现在我正在尝试使用 Bind 函数。

绑定函数的link: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 says:Bind 错误。

我猜这是 sockaddrs 结构(我将值放入其中的方式)中的问题。但是我不知道我需要更改什么以及如何修复它。

我想也许可以使用 WSAGetLastError 函数来查看错误是什么,但我不知道如何打印函数 returns 的值并查看错误是什么(我无法输入调用MessageBox,一个参数EAX(保存returns值的寄存器)) .

有人可以帮我解决 'Bind' 部分的问题吗?

WSAGetLastError

你有几个问题。我将首先为您提供一种检索代表最后一个 WSAGetLastError 的消息的方法(它也适用于 GetLastError)。 Win32 API方式是用FormatMessageWSAGetLastError编辑的错误信息代码return进行转换。来自 MSDN 的关于 FormatMessage 的信息可以在 here, along with an example 中找到,类似于我们将使用的代码。它被定义为:

DWORD WINAPI FormatMessage(

In DWORD dwFlags,
In_opt LPCVOID lpSource,
In DWORD dwMessageId,
In DWORD dwLanguageId,
Out LPTSTR lpBuffer,
In DWORD nSize,
In_opt va_list *Arguments
);

在你的 .DATA? 区域,添加一个变量来存储缓冲区指针,我们将从 FormatMessage:

return
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

您先调用 MessageBoxA 是在破坏 eax。您可能打算先保存它:

mov [ListenSocket],eax
invoke MessageBoxA,NULL,offset SocketSuccess,offset SocketSuccess,MB_OK

此代码中似乎存在许多问题:

mov eax,AF_INET
mov [dword ptr sockaddrs],eax

这是不正确的,因为它适用于 32 位 Integer,我们需要一个 WORD(16 位)。应该是:

mov ax,AF_INET
mov [word ptr sockaddrs],ax

这也需要使用 16 位 WORD 存储在 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