;运行效果
;win32汇编环境,网络编程入门之二
;本教程在前一教程的基础上,研究一下如何得到服务器的返回的信息
;正常的逻辑是连接上了,然后我发送什么,它返回什么,但是这有一个很尴尬的问题。
;就是如何表现出来。因为网络可能有延迟,这个延迟并不确定有多久。
;而程序是顺序执行的,不管是发送了什么,还是干了其它什么,不能让它干等着,尤其是并不确定时间的网络返回
;如果发送了什么,就一直等服务器返回什么,这会导致把主程序卡住。
;所以,我们需要线程。线程在主进程之外保持着运行,这个线程就是连接服务器的线程,它与主进程并行运行。
;需要发送什么给服务器,就告诉连接线程。我们需要得到服务器返回的信息,就从线程里提取这些信息。
;先把上一教程的代码抄进来,再添加一点发送与接收的内容,慢慢地学习一下
;当然,还有很多问题,先让这个实现了,给自已一点成就感,后面的问题慢慢解决。
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
include kernel32.inc
include wsock32.inc ;需要添加的头文件,涉及socket
includelib user32.lib
includelib kernel32.lib
includelib wsock32.lib
; 自定义函数声明
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD ;对话框窗口函数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
MAINDIALOG equ 1
ICO_MAIN equ 1000 ;图标
IDC_IPA1 equ 1001
ID_BUTTON01 equ 41
ID_BUTTON02 equ 42
ID_BUTTON03 equ 43
ID_EDIT01 equ 11
TCP_PORT equ 80 ;端口
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
;DlgName db "MyDialog",0
szErrIP db "无效的服务器IP地址!",0
szErrConnect db "无法连接到服务器!",0
szSucConnect db "可以连接到服务器!",0
szIP db "103.113.93.101",0
szMsg db "提示",0
szFrm db "%d",0
szHello db "POST / HTTP/1.1", 13, 10 ;发送给服务器的字符串,其中13是回车,10是换行。这里的字符串是TCP协议报文。其作用是取得网站的主页
db "HOST:kepai2023.cn", 13, 10 ;这是简单示例,后面我们会慢慢地研究报文这东西。只要符合规范,你发送什么,服务器就返回什么。
db 13, 10,0 ;这样定义字符串,就是让字符紧跟在一起,最后一个是0,就是结束符
.data?
hInstance HINSTANCE ?
hMainhwnd HWND ?
hEdithwnd HWND ?
hW_IP HWND ? ;IP地址控件的句柄
nGetIP dd ? ;存放从IP地址控件取得的值的指针
hSocket dd ?
.const
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke DialogBoxParam, hInstance, MAINDIALOG,NULL, addr DlgProc, NULL
invoke ExitProcess,eax
_WorkThread proc _lParam
LOCAL @stSin:sockaddr_in
LOCAL @szBuffer[1500]:byte ;网络传输的最大单元,1500字节,也就是客户端发过来的数据,一次最大就是1500字节,这是协议规定,
LOCAL @WriteszBuffer[4500]:byte
LOCAL @h01:byte,@h02:byte,@h03:byte,@h04:byte
invoke RtlZeroMemory,addr @stSin,sizeof @stSin
invoke SendMessage,hW_IP,IPM_GETADDRESS,0,offset nGetIP
mov eax,dword ptr [nGetIP]
mov @h04,al
mov @h03,ah
shr eax,16
mov @h02,al
mov @h01,ah
mov bl,@h03
mov bh,@h04
shl ebx,16
mov bl,@h01
mov bh,@h02
mov @stSin.sin_addr,ebx
mov @stSin.sin_family,AF_INET
invoke htons,TCP_PORT
mov @stSin.sin_port,ax
invoke socket,AF_INET,SOCK_STREAM,0
mov hSocket,eax
; 连接到服务器
invoke connect,hSocket,addr @stSin,sizeof @stSin
.if eax == SOCKET_ERROR
invoke MessageBox,NULL,addr szErrConnect,NULL,MB_OK or MB_ICONSTOP
.endif
invoke RtlZeroMemory, addr @szBuffer, 1500
invoke recv, hSocket, addr @szBuffer, 1549, 0 ;想要读取到字节个数,一般是参数2的字节数-1,把\0字符串结尾留出来
invoke GetDlgItem,hMainhwnd,ID_EDIT01
mov hEdithwnd,eax
invoke SendMessage,hEdithwnd,WM_SETTEXT,0,addr @szBuffer
ret
_WorkThread endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL @stWsa:WSADATA
.if uMsg == WM_INITDIALOG
invoke LoadIcon,hInstance,ICO_MAIN
invoke SendMessage,hWnd,WM_SETICON,ICON_BIG,eax
invoke WSAStartup,101h,addr @stWsa
invoke GetDlgItem,hWnd,IDC_IPA1
mov hW_IP,eax
mov ah,103
mov al,113
shl eax,16
mov ah,93
mov al,101
invoke SendMessage,hW_IP,IPM_SETADDRESS,0,eax
mov eax,hWnd
mov hMainhwnd,eax
.elseif uMsg == WM_COMMAND
mov ebx,wParam
.if bx == ID_BUTTON01
invoke CreateThread,NULL,0,offset _WorkThread,0,NULL,0 ;启动连接线程
.elseif bx == ID_BUTTON02
invoke lstrlen, addr szHello
invoke send, hSocket, addr szHello, eax, 0
.endif
.elseif uMsg == WM_CLOSE ;退出程序时记得清除套接字
.if ! hSocket ;如果socket创建失败,则清除它,否则先关闭,再清除
invoke WSACleanup
invoke EndDialog,hWnd,NULL
.else
invoke closesocket,hSocket
xor eax,eax
mov hSocket,eax
invoke WSACleanup
invoke EndDialog,hWnd,NULL
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
DlgProc endp
end start
;下面为rc文件内容
#include "resource.h" //提示缺少该文件,可以在资源里下载
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define MAINDIALOG 1
#define ICO_MAIN 1000 //图标
#define IDC_IPA1 1001
#define ID_BUTTON01 41
#define ID_BUTTON02 42
#define ID_EDIT01 11 //编辑框标识符
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN ICON "Main.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//定义对话框
MAINDIALOG DIALOG 10, 10, 210, 250
STYLE DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
CAPTION "对话框程序模版"
FONT 11, "方正姚体"
BEGIN
CONTROL "输入IP地址:", -1, "Static", WS_CHILD | WS_VISIBLE, 10, 10, 50, 20
CONTROL "",IDC_IPA1,"SysIPAddress32",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,60,10,70,10
PUSHBUTTON "连接网站", ID_BUTTON01, 140,8,60,12
PUSHBUTTON "发送内容", ID_BUTTON02, 140,28,60,12
CONTROL "这里显示的是服务器返回的信息",ID_EDIT01,"Edit",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|ES_MULTILINE|ES_WANTRETURN|ES_AUTOVSCROLL,10, 30, 120, 210,WS_EX_CLIENTEDGE //设置成多行编辑框,按回车时加回车符
END