⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 client2.asm

📁 使用汇编语言实现TCP协议的聊天室例子程序
💻 ASM
字号:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming 2nd Edition>
; by 罗云彬, http://asm.yeah.net
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Client.asm
; 使用 TCP 协议的聊天室例子程序 —— 客户端
; 本例子使用非阻塞模式socket
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff Client2.asm
; rc Client.rc
; Link /subsystem:windows Client2.obj Client.res
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		.386
		.model flat, stdcall
		option casemap :none   ; case sensitive
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	Include 数据
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include		windows.inc
include		user32.inc
includelib	user32.lib
include		kernel32.inc
includelib	kernel32.lib
include		wsock32.inc
includelib	wsock32.lib
include		_Message.inc
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	equ 数据
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN	equ	1000
DLG_MAIN	equ	2000
IDC_SERVER	equ	2001
IDC_USER	equ	2002
IDC_PASS	equ	2003
IDC_LOGIN	equ	2004
IDC_LOGOUT	equ	2005
IDC_INFO	equ	2006
IDC_TEXT	equ	2007
TCP_PORT	equ	9999
WM_SOCKET       equ	WM_USER + 100
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		.data?
hInstance	dd	?
hWinMain	dd	?
hSocket		dd	?
szServer	db	16 dup (?)
szUserName	db	12 dup (?)
szPassword	db	12 dup (?)
szText		db	256 dup (?)

szSendMsg	MSG_STRUCT 10 dup (<>)
szRecvMsg	MSG_STRUCT 10 dup (<>)
dwSendBufSize	dd	?
dwRecvBufSize	dd	?
dbStep		db	?

		.const
szErrIP		db	'无效的服务器IP地址!',0
szErrConnect	db	'无法连接到服务器!',0
szErrLogin	db	'无法登录到服务器,请检查用户名密码!',0
szSpar		db	' : ',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 断开连接
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DisConnect	proc

		invoke	GetDlgItem,hWinMain,IDC_TEXT
		invoke	EnableWindow,eax,FALSE
		invoke	GetDlgItem,hWinMain,IDC_LOGOUT
		invoke	EnableWindow,eax,FALSE

		.if	hSocket
			invoke	closesocket,hSocket
			xor	eax,eax
			mov	hSocket,eax
		.endif

		invoke	GetDlgItem,hWinMain,IDC_SERVER
		invoke	EnableWindow,eax,TRUE
		invoke	GetDlgItem,hWinMain,IDC_USER
		invoke	EnableWindow,eax,TRUE
		invoke	GetDlgItem,hWinMain,IDC_PASS
		invoke	EnableWindow,eax,TRUE
		invoke	GetDlgItem,hWinMain,IDC_LOGIN
		invoke	EnableWindow,eax,TRUE
		ret

_DisConnect	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 连接到服务器
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Connect	proc
		local	@stSin:sockaddr_in,@stMsg:MSG_STRUCT
		local	@szBuffer[512]:byte

		pushad
		invoke	GetDlgItem,hWinMain,IDC_SERVER
		invoke	EnableWindow,eax,FALSE
		invoke	GetDlgItem,hWinMain,IDC_USER
		invoke	EnableWindow,eax,FALSE
		invoke	GetDlgItem,hWinMain,IDC_PASS
		invoke	EnableWindow,eax,FALSE
		invoke	GetDlgItem,hWinMain,IDC_LOGIN
		invoke	EnableWindow,eax,FALSE
		xor	eax,eax
		mov	dbStep,al
		mov	dwSendBufSize,eax
		mov	dwRecvBufSize,eax
;********************************************************************
; 创建 socket
;********************************************************************
		invoke	RtlZeroMemory,addr @stSin,sizeof @stSin
		invoke	inet_addr,addr szServer
		.if	eax ==	INADDR_NONE
			invoke	MessageBox,hWinMain,addr szErrIP,NULL,MB_OK or MB_ICONSTOP
			jmp	_Err
		.endif
		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
;********************************************************************
; 将socket设置为非阻塞模式,连接到服务器
;********************************************************************
		invoke	WSAAsyncSelect,hSocket,hWinMain,WM_SOCKET,FD_CONNECT or FD_READ or FD_CLOSE or FD_WRITE
		invoke	connect,hSocket,addr @stSin,sizeof @stSin
		.if	eax ==	SOCKET_ERROR
			invoke	WSAGetLastError
			.if eax != WSAEWOULDBLOCK
				invoke	MessageBox,hWinMain,addr szErrConnect,NULL,MB_OK or MB_ICONSTOP
				jmp	_Err
			.endif
		.endif
		ret
_Err:
		invoke	_DisConnect
		ret

_Connect	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 发送缓冲区中的数据,上次的数据有可能未发送完,故每次发送前,
; 先将发送缓冲区合并
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_SendData	proc	_lpData,_dwSize

		pushad
;********************************************************************
; 将要发送的内容加到缓冲区的尾部
;********************************************************************
		mov	esi,_lpData
		mov	ecx,_dwSize
		.if	esi && ecx
			push	ecx
			mov	edi,offset szSendMsg
			add	edi,dwSendBufSize
			cld
			rep	movsb
			pop	ecx
			add	dwSendBufSize,ecx
		.endif
;********************************************************************
; 发送缓冲区
;********************************************************************
		@@:
		mov	esi,offset szSendMsg
		mov	ebx,dwSendBufSize
		or	ebx,ebx
		jz	_Ret
		invoke	send,hSocket,esi,ebx,0
		.if	eax ==	SOCKET_ERROR
			invoke	WSAGetLastError
			.if	eax ==	WSAEWOULDBLOCK
				invoke	GetDlgItem,hWinMain,IDC_TEXT
				invoke	EnableWindow,eax,FALSE
				invoke	GetDlgItem,hWinMain,IDOK
				invoke	EnableWindow,eax,FALSE
			.else
				invoke	_DisConnect
			.endif
			jmp	_Ret
		.endif
		sub	dwSendBufSize,eax
		mov	ecx,dwSendBufSize
		mov	edi,offset szSendMsg
		lea	esi,[edi+eax]
		.if	ecx && (edi != esi)
			cld
			rep	movsb
			jmp	@B
		.endif
_Ret:
		popad
		ret

_SendData	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 处理消息
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcMessage	proc
		local	@szBuffer[512]:byte

		mov	ax,szRecvMsg.MsgHead.dwCmdId
		.if	ax ==	CMD_LOGIN_RESP
			.if	szRecvMsg.LoginResp.dbResult
				invoke	MessageBox,hWinMain,addr szErrLogin,NULL,MB_OK or MB_ICONSTOP
				invoke	_DisConnect
			.else
				mov	dbStep,1
				invoke	GetDlgItem,hWinMain,IDOK
				invoke	EnableWindow,eax,FALSE
				invoke	GetDlgItem,hWinMain,IDC_LOGOUT
				invoke	EnableWindow,eax,TRUE
				invoke	GetDlgItem,hWinMain,IDC_TEXT
				invoke	EnableWindow,eax,TRUE
			.endif
		.elseif	ax ==	CMD_MSG_DOWN
			.if	dbStep < 1
				invoke	_DisConnect
			.else
				invoke	lstrcpy,addr @szBuffer,addr szRecvMsg.MsgDown.szSender
				invoke	lstrcat,addr @szBuffer,addr szSpar
				invoke	lstrcat,addr @szBuffer,addr szRecvMsg.MsgDown.szContent
				invoke	SendDlgItemMessage,hWinMain,IDC_INFO,LB_INSERTSTRING,0,addr @szBuffer
			.endif
		.endif
		ret

_ProcMessage	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 接收数据包
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_RecvData	proc

		pushad
		mov	esi,offset szRecvMsg
		mov	ecx,dwRecvBufSize
		add	esi,ecx
;********************************************************************
; 如果缓冲区里数据小于数据包头长度:则先接收数据包头部
; 大于数据包头部,则接收的总长度由数据包头部里的dwLength指定
;********************************************************************
		.if	ecx <	sizeof MSG_HEAD
			mov	eax,sizeof MSG_HEAD
		.else
			mov	eax,szRecvMsg.MsgHead.dwLength
			.if	eax < MSG_HEAD || eax > MSG_STRUCT
				mov	dwRecvBufSize,0
				invoke	_DisConnect
				jmp	_Ret
			.endif
		.endif
;********************************************************************
		sub	eax,ecx
		.if	eax
			invoke	recv,hSocket,esi,eax,NULL
			.if	eax ==	SOCKET_ERROR
				invoke	WSAGetLastError
				.if	eax !=	WSAEWOULDBLOCK
					invoke	_DisConnect
				.endif
				jmp	_Ret
			.endif
			add	dwRecvBufSize,eax
		.endif
		mov	eax,dwRecvBufSize
;********************************************************************
; 如果整个数据包接收完毕,则进行处理
;********************************************************************
		.if	eax >=	sizeof MSG_HEAD
			.if	eax ==	szRecvMsg.MsgHead.dwLength
				invoke	_ProcMessage
				mov	dwRecvBufSize,0
			.endif
		.endif
;********************************************************************
_Ret:
		popad
		ret

_RecvData	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 主窗口程序
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcDlgMain	proc	uses ebx edi esi hWnd,wMsg,wParam,lParam
		local	@stWsa:WSADATA,@stMsg:MSG_STRUCT

		mov	eax,wMsg
;********************************************************************
		.if	eax ==	WM_SOCKET
;********************************************************************
; 处理 Socket 消息
;********************************************************************
			mov	eax,lParam
			.if	ax ==	FD_READ
				invoke	_RecvData
			.elseif	ax ==	FD_WRITE
				invoke	GetDlgItem,hWinMain,IDC_TEXT
				invoke	EnableWindow,eax,TRUE
				invoke	GetDlgItem,hWinMain,IDOK
				invoke	EnableWindow,eax,TRUE
				invoke	_SendData,0,0	;继续发送缓冲区数据
			.elseif	ax ==	FD_CONNECT
				shr	eax,16
				.if	ax ==	NULL	;连接成功则登录
					invoke	lstrcpy,addr @stMsg.Login.szUserName,addr szUserName
					invoke	lstrcpy,addr @stMsg.Login.szPassword,addr szPassword
					mov	@stMsg.MsgHead.dwLength,sizeof MSG_HEAD+sizeof MSG_LOGIN
					mov	@stMsg.MsgHead.dwCmdId,CMD_LOGIN
					invoke	_SendData,addr @stMsg,@stMsg.MsgHead.dwLength
				.else
					invoke	MessageBox,hWinMain,addr szErrConnect,NULL,MB_OK or MB_ICONSTOP
					invoke	_DisConnect
				.endif
			.elseif	ax ==	FD_CLOSE
				call	_DisConnect
			.endif
;********************************************************************
		.elseif	eax ==	WM_COMMAND
			mov	eax,wParam
			.if	(ax == IDC_SERVER) || (ax == IDC_USER) || (ax == IDC_PASS)
				invoke	GetDlgItemText,hWinMain,IDC_SERVER,addr szServer,sizeof szServer
				invoke	GetDlgItemText,hWinMain,IDC_USER,addr szUserName,sizeof szUserName
				invoke	GetDlgItemText,hWinMain,IDC_PASS,addr szPassword,sizeof szPassword
				invoke	GetDlgItem,hWinMain,IDC_LOGIN
				.if	szServer && szUserName && szPassword && !hSocket
					invoke	EnableWindow,eax,TRUE
				.else
					invoke	EnableWindow,eax,FALSE
				.endif
;********************************************************************
			.elseif	ax ==	IDC_TEXT
				invoke	GetDlgItemText,hWinMain,IDC_TEXT,addr szText,sizeof szText
				invoke	GetDlgItem,hWinMain,IDOK
				.if	szText && hSocket
					invoke	EnableWindow,eax,TRUE
				.else
					invoke	EnableWindow,eax,FALSE
				.endif
;********************************************************************
			.elseif	ax ==	IDC_LOGIN
				invoke	_Connect
;********************************************************************
			.elseif	ax ==	IDC_LOGOUT
				invoke	_DisConnect
;********************************************************************
			.elseif	ax ==	IDOK
				.if	szText
					invoke	lstrcpy,addr @stMsg.MsgUp.szContent,addr szText
					invoke	lstrlen,addr @stMsg.MsgUp.szContent
					inc	eax
					mov	@stMsg.MsgUp.dwLength,eax
					add	eax,sizeof MSG_HEAD+MSG_UP.szContent
					mov	@stMsg.MsgHead.dwLength,eax
					mov	@stMsg.MsgHead.dwCmdId,CMD_MSG_UP
					invoke	_SendData,addr @stMsg,@stMsg.MsgHead.dwLength
					invoke	SetDlgItemText,hWinMain,IDC_TEXT,NULL
					invoke	GetDlgItem,hWinMain,IDC_TEXT
					invoke	SetFocus,eax
				.endif
			.endif
;********************************************************************
		.elseif	eax ==	WM_CLOSE
			.if	! hSocket
				invoke	WSACleanup
				invoke	EndDialog,hWinMain,NULL
			.endif
;********************************************************************
		.elseif	eax ==	WM_INITDIALOG
			push	hWnd
			pop	hWinMain
			invoke	LoadIcon,hInstance,ICO_MAIN
			invoke	SendMessage,hWnd,WM_SETICON,ICON_BIG,eax
			invoke	WSAStartup,101h,addr @stWsa
			invoke	SendDlgItemMessage,hWinMain,IDC_SERVER,EM_SETLIMITTEXT,15,0
			invoke	SendDlgItemMessage,hWinMain,IDC_USER,EM_SETLIMITTEXT,11,0
			invoke	SendDlgItemMessage,hWinMain,IDC_PASS,EM_SETLIMITTEXT,11,0
			invoke	SendDlgItemMessage,hWinMain,IDC_TEXT,EM_SETLIMITTEXT,250,0
;********************************************************************
		.else
			mov	eax,FALSE
			ret
		.endif
		mov	eax,TRUE
		ret

_ProcDlgMain	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 程序开始
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
		invoke	GetModuleHandle,NULL
		mov	hInstance,eax
		invoke	DialogBoxParam,eax,DLG_MAIN,NULL,offset _ProcDlgMain,0
		invoke	ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		end	start

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -