WIN32汇编语言教程:第16章 TCP/IP和网络通信 · 16.3 TCP协议编程(3)

                  local  @stWsa:WSADATA

 

                  mov    eax,wMsg

              .if    eax == WM_SOCKET

;********************************************************************

; 处理 Socket 消息

;********************************************************************

                      mov    eax,lParam

                      .if    ax ==  FD_READ

                              invoke _RecvData,wParam

                      .elseif ax ==  FD_WRITE

                          invoke EnableWindow,hWinOK,TRUE

                  .elseif ax ==  FD_CONNECT

                         shr    eax,16

                          .if    ax ==  NULL

                                 invoke SetWindowText,hWinConnect,\

                                             addr szDisConnect

                                      invoke EnableWindow,hWinConnect,TRUE

                                     invoke EnableWindow,hWinServer,FALSE

                                      invoke EnableWindow,hWinText,TRUE

                                     invoke EnableWindow,hWinOK,TRUE

                                      invoke SetFocus,hWinText

                              .else

                                      invoke _DisConnect

                                     invoke MessageBox,hWinMain,\

                                             offset szErrConnect,NULL,\

                                             MB_OK or MB_ICONWARNING

                             .endif

                     .elseif ax ==  FD_CLOSE

                             call      _DisConnect

                      .endif

;********************************************************************

             .elseif eax == WM_COMMAND

                      mov    eax,wParam

                      .if    ax ==  IDOK

                             invoke _SendData

                     .elseif ax ==  IDC_CONNECT

                              .if    hSocket

                                     invoke _DisConnect

                             .else

                                      call      _Connect

                             .endif

                     .endif

;********************************************************************

              .elseif eax == WM_CLOSE

                      invoke _DisConnect

                      invoke WSACleanup

                      invoke EndDialog,hWinMain,NULL

;********************************************************************

                  .elseif eax == WM_INITDIALOG

                         push      hWnd

                     pop    hWinMain

                     invoke GetDlgItem,hWnd,IDC_SERVER

                      mov    hWinServer,eax

                     invoke GetDlgItem,hWnd,IDOK

                     mov    hWinOK,eax

                      invoke GetDlgItem,hWnd,IDC_TEXT

                     mov    hWinText,eax

                     invoke GetDlgItem,hWnd,IDC_CONNECT

                     mov    hWinConnect,eax

                      invoke GetDlgItem,hWnd,IDC_INFO

                      mov    hWinInfo,eax

                     invoke SetWindowText,hWinServer,addr szIP

                     invoke WSAStartup,101h,addr @stWsa

;********************************************************************

              .else

                     mov    eax,FALSE

                     ret

              .endif

              mov    eax,TRUE

             ret

 

_ProcDlgMain      endp

;####################################################################

; 程序开始

;####################################################################

start:

              invoke GetModuleHandle,NULL

              invoke DialogBoxParam,eax,DLG_MAIN,NULL,offset_ProcDlg Main,0

             invoke ExitProcess,NULL

;####################################################################

              end    start

在图16.8的模型中,已经了解了客户端程序大致的工作方式,但是到具体实现的时候,各种语句应该如何和Windows的消息驱动体系配合呢,上述源代码的结构看上去似乎比较松散,但是从图16.10中就可以看出它的工作流程。


图16.10 TCP客户端程序的常见结构

请读者结合图16.10中的数字序号来分析源代码,初始化WinSock库的WSAStartup函数被安排在窗口的初始化消息中(图中的①),当程序需要退出时,程序调用WSACleanup函数卸载WinSock库(图中的⑧)。

当用户要求连接时(比如例子中用户输入了IP地址并按下了“连接”按钮,见图16.10中的②),程序使用socket函数创建套接字,套接字的类型必须是流套接字,因为只有它是使用TCP协议的:

   invoke socket,AF_INET,SOCK_STREAM,0

   mov    hSocket,eax

   invoke WSAAsyncSelect,hSocket,hWinMain,\

          WM_SOCKET,FD_CONNECT or FD_READ or FD_CLOSE or FD_WRITE

套接字创建以后,应该使用WSAAsyncSelect函数将通知消息以自定义的ID(例子中使用WM_SOCKET消息,它被预先定义为WM_USER+100)绑定到窗口过程中,这样就可以在适当的时候收到系统的通知消息,当收到消息的时候,lParam的低16位包括了通知码,高16位为出错信息,wParam参数指定了发生消息的套接字句柄。对于用于客户端的流套接字来说,在使用WSAAsyncSelect函数时必须包含FD_CONNECT,FD_READ,FD_WRITE和FD_CLOSE通知码。

完成这些事情后,接下来就可以使用connect函数去连接服务器了。

1. 连接到服务器

connect函数将一个流套接字连接到指定IP地址的指定端口上,它仅适用于流套接字,因为数据报套接字不是面向连接的。connect函数的用法是:

   invoke connect,s,lpsockaddr,len

参数s指定用于连接的套接字句柄,lpsockaddr参数指向一个sockaddr_in结构,用来指定要连接到的服务器的IP地址和端口,这个结构在前面介绍的bind函数中已经使用过,len参数则指定sockaddr_in结构的长度。

当连接成功的时候,函数返回0,否则返回值是SOCKET_ERROR,但是当套接字工作在非阻塞模式时,函数返回的时候连接还没来得及完成,返回值肯定会是SOCKET_ERROR,但这并不意味着以后连接就不会成功,如果出错代码显示为WSAEWOULDBLOCK值,表示出错是因为操作尚未完成引起的,这时应该等待,否则才是真正的出错。

上页:第16章 TCP/IP和网络通信 · 16.3 TCP协议编程(2) 下页:第16章 TCP/IP和网络通信 · 16.3 TCP协议编程(4)

第16章 TCP/IP和网络通信

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号