计算机网络实验指导书(详细版)

计算机网络实验指导书

11、熊桂喜 等译。计算机网络。清华大学出版社2002年7月。

附录1 实验原理

1. 基本术语

客户机:Client,也称为工作站端或客户端,它是通信的发起端。 服务器:Server,它是通信的等待方。

图4.1显示了客户端和服务器端工作方式的不同。软件运行的界面如图4.2所示。

图4.1 TCP C/S模型

图4.2 软件运行界面

2. 聊天室客户端的实现

客户端程序包括程序文件client.asm和资源文件client.rc。资源文件确定了客户端的界面形式。程序文件的流程图如图图4.3所示。

①它先调用WSAStartup函数初始化WinSock库。

②当用户输入IP并点击连接按钮后,使用Socket函数创建流套接字,使用WSAAsyncSelect函数将通知消息自定义的ID(即:hSocket)绑定到窗口过程中,

第 31 页 共 64 页

计算机网络实验指导书

再使用connect函数去连接服务器。

③连接成功时,系统的FD_CONNECT会通知消息给客户端窗口。 ④连接成功后就可以传输数据了。

A. 系统原语recv收到数据后,发送系统通知消息FD_READ,客户端将从缓冲区szReadBuffer中读取数据。

B. 客户端需要发送数据时,从对话框中获取数据,写入缓冲区@szBuffer,调用系统原语send函数发送出数据,在收到系统FD_WRITE通知消息后,继续发送数据。

C. 在缓冲区满或发送失败时,客户端将重发并等待FD_WRITE通知消息的到来。

⑤连接失败则调用closesocket函数断开连接。

⑥用户在数据传输完毕,调用closesocket函数断开连接。 ⑦客户端收到FD_CLOSE通知消息时,连接已经断开。

⑧在客户端关闭时,调用WSACleanup函数卸载WinSock库。

图4.3 客户端程序结构

图4.4 服务器端程序结构

3. 聊天室服务器端的实现

服务器端程序包括程序文件server.asm和资源文件server.rc。资源文件确定了服务器端的界面形式。程序文件的流程图如图图4.4所示。

在WinSock库的加载和卸载,何时去读取套接字,发送数据时的流量控制等方面,服务器端和客户端的工作原理是一样的。

第 32 页 共 64 页

计算机网络实验指导书

当服务器端准备在端口9999提供服务时,需要创建流套接字,并设置为非阻塞模式,再使用bind函数将套接字hSocket和端口@stSin绑定。接着调用函数listen让套接字进入监听状态,并指定监听队列允许保持的尚未处理的最大连接数为5。

这样,主程序收到系统FD_ACCEPT通知消息后,调用accept接受客户机的连接请求,调用_AddClient将其加入到客户端列表中,并统计当前的用户数dwCount。收到系统FD_READ通知消息后,服务器会调用_RecvData处理接收到的TCP包。收到系统FD_CLOSE通知消息后,服务器会调用_RemoveClient从客户端列表中删除当前用户的sochet。

附录2 实验源程序

1、服务器端

; Server.asm

; 使用 TCP 协议的聊天室例子程序 —— 服务器端 ; 使用 nmake 或下列命令进行编译和链接: ; ml /c /coff Server.asm ; rc Server.rc

; Link /subsystem:windows Server.obj Server.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 ; equ 数据 DLG_MAIN equ 2000 IDC_INFO equ 2001 IDC_COUNT equ 2002

WM_SOCKET equ WM_USER + 100 TCP_PORT equ 9999

MAX_SOCKET equ 100 ;聊天室最大容量 ; 数据段 .data? hWinMain dd ? hSocket dd ? dwCount dd ?

第 33 页 共 64 页

计算机网络实验指导书

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 ; 代码段 .code

; 在客户端列表中加上一个 socket _AddClient proc _hSocket invoke

WSAAsyncSelect,_hSocket,hWinMain,WM_SOCKET,FD_READ FD_CLOSE

xor ebx,ebx mov esi,offset stTable .while ebx < MAX_SOCKET .if ! dword ptr [esi] push _hSocket pop [esi] inc dwCount invoke

SetDlgItemInt,hWinMain,IDC_COUNT,dwCount,FALSE

ret .endif inc ebx add esi,4 .endw invoke closesocket,_hSocket ret

_AddClient endp

; 从客户端列表中去掉一个 socket _RemoveClient proc _hSocket xor ebx,ebx mov esi,offset stTable mov edi,_hSocket .while ebx < MAX_SOCKET .if [esi] == edi invoke closesocket,[esi] mov dword ptr [esi],0 dec dwCount

第 34 页 共 64 页

or 计算机网络实验指导书

invoke

SetDlgItemInt,hWinMain,IDC_COUNT,dwCount,FALSE

ret .endif inc ebx add esi,4 .endw ret

_RemoveClient endp ; 处理接收到的TCP包

_RecvData proc _hSocket local @dwRecv invoke RtlZeroMemory,addr szReadBuffer,sizeof szReadBuffer invoke recv,_hSocket,addr szReadBuffer,sizeof szReadBuffer,NULL .if eax != SOCKET_ERROR mov @dwRecv,eax invoke wsprintf,addr szBuffer,addr szFormat,\\ _hSocket,addr szReadBuffer ; 按照客户端列表逐一发送 invoke GetDlgItem,hWinMain,IDC_INFO mov ebx,eax invoke GetWindowTextLength,ebx 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 proc

第 35 页 共 64 页

联系客服:779662525#qq.com(#替换为@) 苏ICP备20003344号-4