;运行效果
;win32汇编环境,网络编程入门之四
;本教程学一下,怎么把得到的主页的数据变得我们认识
;在前面的教程里,我们得到某个网站的主页。但是发现里面一堆乱码。
;仔细看看,里面有一句:<meta charset="utf-8">,这句的意思是,该网页使用的是UTF8编码。这就是显示乱码的原因。
;这是因为,网页的编码是UTF8,而我们程序的编码是ASCII码的,接收到这些数据,除了里面ASCII码的内容外,其它的不认识,只能显示出乱码一堆。
;如果我们尝试换个IP试试,连接其它网站,却发现一发送内容,会导致程序崩溃。
;这个原因是因为我们的示例程序,连接的都是小容量数据的网页。而大部分的网页,数据量很大,我们的示例程序并没有处理大数据量的逻辑。所以一运行,直接崩溃。
;所以,要改的事很多,一点点来,都是靠积累着变好的。
;先来解决编码的问题
;这里要先了解一下UTF8编码,它是可变长的编码,简单地说,它的第1个字节内的某个值决定了,这个字符总共有多少个字节。
;这个字符或许是2个字节,或许是3个字节,也许4个,最多不超过4个。当然,具体的很复杂,有兴趣可以上网查查这个编码的资料,那也可以写本书了。
;单个字符没什么问题,要是一篇长长的文章,这就很要命了。
;幸运的是,有函数可以帮我们搞掂这些事儿,把它重新整理出来。我们也只需要最基本的功能就够了,就是让我们能认得那些字符。
;我们这一教程,就是想办法把这个问题搞掂它。
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.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
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 @Rec_szBuffer[4500]:byte
LOCAL @h01:byte,@h02:byte,@h03:byte,@h04:byte
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 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 SendMessageW,hEdithwnd,WM_SETTEXT,0,addr @Rec_szBuffer ;因为要显示中文,故而用Unicode编码,只能用SendMessageW发送
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 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