计算机网络实验指导书(详细版) 下载本文

内容发布更新时间 : 2024/5/18 15:26:13星期一 下面是文章的全部内容请认真阅读。

计算机网络实验指导书

include kernel32.inc ;32位内核库 includelib kernel32.lib include wsock32.inc ;32位1.1版本的套接字库 includelib wsock32.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; equ 数据

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;对应的窗口资源 DLG_MAIN equ 2000 IDC_INFO equ 2001 IDC_COUNT equ 2002

;通知消息使用的ID,必须选择大于WM_USER的值,本程序选择比WM_USER大100的值作为ID

WM_SOCKET equ WM_USER + 100 TCP_PORT equ 9999 ;用于建立套接字的TCP端口号 MAX_SOCKET equ 100 ;聊天室最大用户容量

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 数据段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.data?

;窗口句柄及建立的套接字 hWinMain dd ? hSocket dd ? ;当前连接的客户计数 dwCount dd ?

;recv原语收到的TCP数据包缓冲地址 szReadBuffer db 32768 dup (?) ;发送缓冲区

szBuffer db 32768 dup (?)

;在线客户列表,用于客户的添加与删除 stTable dd MAX_SOCKET dup (?) .const ;出错提示信息 szErrBind db '无法绑定到TCP端口9999,请检查是否有其它程序在使用!',0 ;在主窗口中显示客户信息的区分标题

szFormat db '【客户端#x】- %s',0dh,0ah,0

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 代码段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

第 56 页 共 64 页

计算机网络实验指导书

>>

.code

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 在客户端列表中加上一个 socket

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;线程1:在客户端列表中加上一个 socket _AddClient proc _hSocket ;设置套接字_hSocket在窗口hWinMain的工作模式,明确使用的消息ID WM_SOCKET和响应的通知消息类型FD_READ or FD_CLOSE

invoke WSAAsyncSelect,_hSocket,hWinMain,WM_SOCKET,FD_READ or FD_CLOSE

;获得客户列表地址

xor ebx,ebx mov esi,offset stTable .while ebx < MAX_SOCKET ;搜索客户列表,找到空地址,把新客户添加进去 .if ! dword ptr [esi] push _hSocket pop [esi] inc dwCount ;客户数增加1 ;窗口上客户数IDC_COUNT增加1,且不允许修改 invoke SetDlgItemInt,hWinMain,IDC_COUNT,dwCount,FALSE ret .endif ;调整指针,指向下一个客户的套接字 inc ebx add esi,4 .endw ;关闭套接字_hSocket invoke closesocket,_hSocket ret

_AddClient endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 从客户端列表中去掉一个 socket

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_RemoveClient proc _hSocket

;线程2:从客户端列表中去掉一个 socket ;获得客户列表地址 xor ebx,ebx mov esi,offset stTable

第 57 页 共 64 页

计算机网络实验指导书

mov edi,_hSocket .while ebx < MAX_SOCKET ;找到该套接字则关闭之 .if [esi] == edi invoke closesocket,[esi] mov dword ptr [esi],0 ;连接客户的数量减1 dec dwCount ;更新窗口中连接客户数,禁止修改 invoke SetDlgItemInt,hWinMain,IDC_COUNT,dwCount,FALSE ret .endif ;调整指针,指向下一个客户的套接字 inc ebx add esi,4 .endw ret

_RemoveClient endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 处理接收到的TCP包

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;线程3:处理接收到的TCP包 _RecvData proc _hSocket

;局部变量@dwRecv,保存收包成功后的状态值 local @dwRecv ;接收缓冲区szReadBuffer清空 invoke RtlZeroMemory,addr szReadBuffer,sizeof szReadBuffer ;接收TCP数据包,存入szReadBuffer invoke recv,_hSocket,addr szReadBuffer,sizeof szReadBuffer,NULL .if eax != SOCKET_ERROR ;保存状态值 mov @dwRecv,eax ;把消息从szReadBuffer复制到szBuffer invoke wsprintf,addr szBuffer,addr szFormat,_hSocket,addr szReadBuffer ;******************************************************************** ; 按照客户端列表逐一发送

;******************************************************************** ;获得窗口IDC_INFO中已经显示的客户信息

invoke GetDlgItem,hWinMain,IDC_INFO

mov ebx,eax ;计算信息长度 invoke GetWindowTextLength,ebx

第 58 页 共 64 页

计算机网络实验指导书

;添加空行 invoke SendMessage,ebx,EM_SETSEL,eax,eax ;插入信息 invoke SendMessage,ebx,EM_REPLACESEL,FALSE,addr szBuffer ;获得客户列表地址 mov esi,offset stTable xor ebx,ebx ;把消息向列表中客户逐一发送 .while ebx < MAX_SOCKET mov edi,[esi] .if edi invoke lstrlen,addr szBuffer ;计算信息长度 invoke send,edi,addr szBuffer,eax,0 ;发送信息 .endif ;调整指针,指向下一个客户的套接字 add esi,4 inc ebx .endw .endif ret

_RecvData endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 初始化 Socket,绑定到服务TCP端口并监听

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;初始化函数_Init _Init proc ;局部变量,保存WinSock库初始化后的信息 local @stWsa:WSADATA ;局部变量,用于组合IP地址和端口号 local @stSin:sockaddr_in ;加载并初始化WinSock库,版本号为1.1,返回信息在@stWsa中 invoke WSAStartup,101h,addr @stWsa ;建立套接字hSocket,类型为流套接字,协议类型为TCP invoke socket,AF_INET,SOCK_STREAM,0 mov hSocket,eax ;设置套接字hSocket在窗口hWinMain的工作模式,明确使用的消息ID WM_SOCKET和响应的通知消息类型FD_ACCEPT

invoke WSAAsyncSelect,hSocket,hWinMain,WM_SOCKET,FD_ACCEPT ;变量@stSin清零 invoke RtlZeroMemory,addr @stSin,sizeof @stSin ;组合IP地址和端口号,得到结构体@stSin invoke htons,TCP_PORT ;转换十进制的TCP端口号

第 59 页 共 64 页

计算机网络实验指导书

mov @stSin.sin_port,ax ;TCP端口 mov @stSin.sin_family,AF_INET ;地址类型,WINDOWS必须为AF_INET mov @stSin.sin_addr,INADDR_ANY ;32位IP地址 ;把套接字hSocket与@stSin绑定

invoke bind,hSocket,addr @stSin,sizeof @stSin .if eax == SOCKET_ERROR ; 弹出“错误”对话框,显示出错信息szErrBind invoke MessageBox,hWinMain,addr szErrBind,NULL,\\ MB_OK or MB_ICONWARNING ;绑定出错,向hWinMain发送WM_CLOSE消息 invoke SendMessage,hWinMain,WM_CLOSE,0,0 .else ;绑定成功,服务器进入监听状态

;监听队列允许保存的最大未处理连接数量为5

invoke listen,hSocket,5 .endif ret _Init endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 主窗口程序

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;主窗口程序

;窗口句柄hWnd,消息类型wMsg,参数类型wParam,参数值lParam _ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam mov eax,wMsg

;******************************************************************** ; 处理 Socket 消息

;******************************************************************** .if eax == WM_SOCKET mov eax,lParam .if ax == FD_ACCEPT ;监听中的流套接字检测到有连接进入,启动添加客户线程 invoke accept,wParam,0,0 invoke _AddClient,eax .elseif ax == FD_READ ;套接字收到对端发送来的数据包,启动TCP数据包接收线程

invoke _RecvData,wParam

.elseif ax == FD_CLOSE ;检测到套接字对应连接被关闭,断开其与服务器的连接

invoke _RemoveClient,wParam

.endif

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

第 60 页 共 64 页