;运行效果
;win32汇编环境,网络编程入门之五
;本教程学一下,怎么读取更多的数据量。
;在上一教程里,我们学会了读取网站返回的数据,但数据量太大的时候,程序无法接收,导致崩溃。
;在这个教程里,我们找到一个有上万字节的网页进行读取,并解决崩溃的问题
;主要的方法是让连接后,访问网站时延迟一点时间,比如1分钟。等获取完返回的数据再结束
;这个延迟的方法,采用了GetTickCount函数,得到当前时间,起后让其循环读取获得的数据,规定循环的时间为1分钟,1分钟后结束。
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.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 ;图标
ID_BUTTON01 equ 41
ID_BUTTON02 equ 42
ID_BUTTON03 equ 43
ID_EDIT01 equ 11
TCP_PORT equ 80 ;端口
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
szErrIP db "无效的服务器IP地址!",0
szErrConnect db "无法连接到服务器!",0
szSucConnect db "可以连接到服务器!",0
szIP db "103.113.93.101",0
szHello db "GET /A/A01.html HTTP/1.1", 13, 10
db "HOST:www.kepai2023.cn", 13, 10
db 13, 10, 0
.data?
hInstance HINSTANCE ?
hMainhwnd HWND ?
hEdithwnd HWND ?
hW_IP HWND ? ;IP地址控件的句柄
nGetIP dd ? ;存放从IP地址控件取得的值的指针
hSocket dd ?
dwLastTime dd ?
hbytesRead 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 @Rec_szBuffer[4500]:byte
LOCAL @stCR:CHARRANGE
invoke RtlZeroMemory,addr @stSin,sizeof @stSin
invoke inet_addr,addr szIP ;将字符串类型的IP地址进行转换,转换成网络字节序
mov @stSin.sin_addr,eax
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 GetTickCount ;得到当前时间
mov dwLastTime,eax ;保存当前时间
.while hSocket ;开始循环读取返回的数据
invoke GetTickCount ;每次读取后再得到当前时间
sub eax,dwLastTime ;当前时间减去前面保存的时间
.break .if eax >= 60 * 1000 ;如果差距达到1分钟,则跳出读取返回数据的循环
invoke RtlZeroMemory, addr @szBuffer, 1500
invoke recv, hSocket, addr @szBuffer, 1549, 0 ;想要读取到字节个数,一般是参数2的字节数-1,把\0字符串结尾留出来
invoke MultiByteToWideChar,65001,0,addr @szBuffer,1549,addr @Rec_szBuffer,4500 ;将接收到的utf-8编码的字符串转换为Unicode编码的字符串,CP_UTF8的值是65001
invoke GetWindowTextLength,hEdithwnd ;开始让数据紧跟着前面的数据显示在编辑框里面
mov @stCR.cpMin,eax
mov @stCR.cpMax,eax
invoke SendMessageW,hEdithwnd,EM_EXSETSEL,0,addr @stCR
invoke SendMessageW,hEdithwnd,EM_REPLACESEL,FALSE,addr @Rec_szBuffer
.endw
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
mov eax,hWnd
mov hMainhwnd,eax
invoke GetDlgItem,hMainhwnd,ID_EDIT01
mov hEdithwnd,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 SendMessageW,hEdithwnd,WM_SETTEXT,0,0 ;清空编辑框
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 ID_BUTTON01 41
#define ID_BUTTON02 42
#define ID_EDIT01 11 //编辑框标识符
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN ICON "Main.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//定义对话框
MAINDIALOG DIALOG 10, 10, 210, 230
STYLE DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
CAPTION "对话框程序模版"
FONT 11, "方正姚体"
BEGIN
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|WS_VSCROLL,10, 10, 120, 210,WS_EX_CLIENTEDGE //设置成多行编辑框,按回车时加回车符
END