网络编程复习题 - 图文

更新时间:2024-01-06 11:49:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

计算机网络编程复习题

1、说明C/S模式的概念、工作过程以及基于因特网的C/S模式的应用程序的特点。

答:网络应用进程之间通信时,普遍采用了客户机/服务器(Client/Server)交互模式,简称C/S模式。客户机和服务器均是运行在计算机中网络协议栈之上的应用进程,它们借助网络协议栈进行通信。而C/S模式描述了进程之间服务与被服务的关系。客户机是服务的请求方(被服务方),服务器是服务的提供方。

服务器的工作过程是:

1) 打开一通信通道,并告知服务器所在的主机,它愿意在某一公认的地址上

(熟知端口)接收客户请求。 2) 等待客户的请求到达该端口。

3) 服务器接收到服务请求,处理该请求并发送应答信号。为了能并发地接收

多个客户的服务请求,要激活一个新进程或新线程来处理这个客户请求。服务完成后,关闭此新进程与客户的通信链路,并终止。 4) 返回第二步,等待并处理另一客户请求。 5) 在特定的情况下,关闭服务器 客户方的工作过程:

1) 打开一通信通道,并连接到服务器所在主机的特定监听端口。

2) 向服务器发送请求报文,等待并接收应答;继续提出请求。与服务器的会

话按照应用协议进行。

3) 通信结束后,关闭通信通道并终止。 基于因特网的C/S模式的应用程序的特点有:

1) 客户和服务器都是软件进程。它指出的是提供服务和被服务的关系。 2) 非对称性:服务器通过网络提供服务,客户通过网络使用服务,这种不对

称性体现在软件结构和工作过程上。

3) 对等性:客户和服务器必有一套共识的约定,必与以某种应用层协议相联,

并且协议必须在通信的两端实现。

4) 服务器的被动性:服务器必须先行启动,只要有客户请求,就立即处理并

响应。但决不主动提供服务。

5) 客户机的主动性:一次请求与服务的过程是由客户机首先激发的。客户可

以随时向服务器提出请求,通过网络得到服务。

6) 一对多:一个服务器可以为多个客户服务,客户也可以连接到多个服务器。 7) 分布性与共享性:资源被组织、存储在分散的服务器端,可通过网络为多

个客户端使用。

2、画框图说明无连接数据报套接字编程的基本步骤。

答:无连接的套接字编程有两种模式:C/S(客户/服务器)模式和P2P(对等)模式。 (1)对等模式数据报套接字的编程模型:

(2)客户/服务器模式编程模型

3、画框图说明服务器端和客户机端操作流式套接字的基本步骤。

4、使用CAsyncSocket类编写基于流式套接字网络应用程序的一般步骤是什么?CAsyncSocket可以接收和处理哪些网络事件?当这些网络事件发生时,MFC框架做何处理?

答:使用CAsyncSocket类编写基于流式套接字网络应用程序的一般步骤如下:

1) 从CAsyncSocket类派生出自己的套接字类。

2) 对从CAsyncSocket类派生出来的套接字类进行修改,主要是对自己感兴趣的

消息处理函数进行重载,使得在套接字上发生特定的事件时,能做出相应的响应。 3) 服务器端:

a) 构造一个监听套接字。比如:

CListenSocket sockSrv; // CListenSocket是从CAsyncSocket类派生出来的监听套接字类

b) 创建SOCKET句柄,绑定到指定端口。比如:

sockSrv.Create(nPort); // nPort是套接字监听的端口号。

c) 启动监听,准备接受客户方连接请求。比如:

sockSrv.Listen();

d) 在监听套接字对象的FD_ACCEPT事件处理函数中,创建一个连接套接

字来接受客户方的连接请求。比如:

CRecvSocket sockRecv; // CRecvSocket是从CAsyncSocket类派生出来的连接套接字类

sockSrv.Accept(sockRecv);

e) 在连接套接字对象的FD_READ事件处理函数中,调用连接套接字对象的

成员函数Receive()来接收从客户发来的数据。比如: sockRecv.Receive(pBuf,nLen); f)

调用连接套接字类对象的成员函数Send()把数据发送给客户方。比如: sockRecv.Send(pBuf,nLen);

g) 关闭连接套接字对象,结束与客户方的通信。比如:

sockRecv.Close();

其中监听套接字和连接套接字可以是同一个CAsyncSocket的派生类的对象。 4) 客户端:

a) 构造一个套接字,并使用默认参数创建它。比如:

CClientSocket sockClient; sockClient.Create();

b) 与服务器方建立连接。比如:

sockClient.Connect(strServerAddr,nPort);

c) 使用套接字对象的Send()成员函数把数据发送到服务器。比如:

sockClient.Send(pBuf,nLen);

d) 在套接字对象的FD_READ事件处理函数中,调用连接套接字对象的成员

函数Receive()来接收从服务器方发来的数据。比如: sockClient.Receive(pBuf,nLen); e) 关闭套接字对象。比如:

sockClient.Close();

CAsyncSocket类可以接收和处理下述网络事件:

1) FD_READ事件:通知有数据可读。

2) FD_WRITE事件:通知可以写数据。

3) FD_ACCEPT事件:通知监听套接字有连接请求可以接受。

4) FD_CONNECT事件:通知请求连接的套接字,连接的要求已被处理。 5) FD_CLOSE事件:通知套接字已关闭。 6) FD_OOB事件通知:通知将有带外数据到达。

当上述的网络事件发生时,MFC框架按照Windows的消息驱动机制,把消息发送给相应的套接字对象,并调用作为该对象成员函数的事件处理函数对相应的网络事件进行处理。

5、说明基于流式套接字的CSocket类编程模型 (1)服务器端

CSocket sockServ; // 创建空的服务器端监听套接字对象。

sockServ.Create( nPort ); // 用众所周知的端口,创建监听套接字对象的底层套接字句柄。

sockServ.Listen();// 启动对于客户端连接请求的监听。 CSocket sockRecv; // 创建空的服务器端连接套接字对象。

sockServ.Accept( sockRecv); // 接收客户端的连接请求,并将其他任务转交连接套接字对象。

//创建文件对象并关联到连接套接字对象。 CSockFile* file ;

file = new CSockFile( &sockRecv);

// 创建用于输入/输出的归档对象,并必须关联到文件对象。 CArchive* arIn, arOut;

arIn = CArchive(&file, CArchive::load); arOut = CArchive( &file, CArchive::store); arIn >> dwValue; // 进行数据输入。

adOut << dwValue; // 进行数据输出。输入或输出可以反复进行。 sockRecv.Close();// 传输完毕,关闭套接字对象。 sockServ.Close(); (2)客户端

CSocket sockClient; // 创建空的客户机端套接字对象。

sockClient.Create( ); // 创建套接字对象的底层套接字。 sockClient.Connect( strAddr, nPort ); // 请求连接到服务器。 //创建文件对象,并关联到套接字对象。 CSockFile* file ;

file = new CSockFile( &sockClient);

// 创建用于输入/输出的归档对象,归档对象必须关联到文件对象。 CArchive* arIn, arOut;

arIn = CArchive(&file, CArchive::load); arOut = CArchive( &file, CArchive::store); arIn >> dwValue; // 进行数据输入。

adOut << dwValue; // 进行数据输出。可以反复进行。 sockClient.Close(); // 传输完毕,关闭套接字对象。

6、现已经声明如下变量,其中num的值是已经创建并存储在数组s中套接字的数量。现要求通过select模型来检查数组s中的套接字是否有数据可以接收,只有当至少一个套接实际上有数据可接收才会从select中返回。若某一套接字上有数据可以接收,则通过调用函数MyRecv(SOCKET s)来完成数据接收和处理操作。试补充完成如下程序来实现上述功能。

SOCKET s[10]; fd_set fdread; int num; 答: int i,ret;

FD_ZERO(&fdread); for(i=0;i

if((ret=select(0,&fdread,NULL,NULL,NULL)) ==SOCKET_ERROR) {

…//出错处理 }

if(ret>0) {

for(i=0;i

if(FD_ISSET(s[i],&fdread)) MyRecv(s[i]); }

7、使用WSAAsyncSelect异步I/O模型编写一个基于对话框的网络应用程序,请根据要求,完成以下题目:

1)

当在套接字MySocket上有数据可读或者对方释放与MySocket的连接时,向对话框发送一条消息号为WM_MYSOCKMSG消息。该对话框的句柄保存在变量hWnd中。请写出能完成该功能的WSAAsyncSelect()函数调用语句。 答:完成该功能的语句如下:

WSAAsyncSelect(MySocket, hWnd, WM_MYSOCKMSG, FD_READ | FD_CLOSE);

2) 对话框通过调用消息处理函数void MyMsgHandle(WPARAM wParam,

LPARAM lParam)完成对WM_MYSOCKMSG消息的处理。为实现该功能,如何对MFC生成的对话框应用程序进行修改?

答:在对话框中添加自定义消息的方法为:

a) 定义消息号:可以使用宏定义语句“#define”增加一个用户自定义消息,

该定义的作用范围应该包括整个类。该消息号不能与现有消息的消息相同。通常用户自定义的消息号从系统定义的常量WM_USER开始分配。例如:

#define WM_MYSOCKMSG (WM_USER+1)

b) 增加消息处理函数:在对话框中增加一个成员函数,用于对自定义消息进

行处理。比如:

void MyMsgHandle(WPARAM wParam, LPARAM lParam);

c) 在对话框类的头文件中,移动消息处理函数声明到类的AFX_MSG块,

并在函数声明前面添加afx_msg。比如:

// Generated message map functions //{{AFX_MSG(CTestDlg)

afx_msg void MyMsgHandle(WPARAM wParam, LPARAM lParam); …

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

d) 在类的实现文件的消息块中,使用ON_MESSAGE宏指令将消息映射到

消息处理函数。比如:

BEGIN_MESSAGE_MAP(CTestDlg, CDialog) … …

//}}AFX_MSG_MAP

ON_MESSAGE(WM_MYMSG, MyMsgHandle) //{{AFX_MSG_MAP(CTestDlg)

END_MESSAGE_MAP()

e) 在消息处理函数中添加代码,以实现对消息的处理。传递给消息处理函数

的参数wParam和lParam携带了与消息相关的更详细的信息。

3) 若接收到对方发送的消息,将消息直接输出;若是对方释放连接,则显示“对

方掉线”,然后关闭套接字。请给出实现该功能的消息处理函数void MyMsgHandle(WPARAM wParam, LPARAM lParam)。 答:相应的关键代码如下:

switch(WSAGETSELECTEVENT(lParam)) {

case FD_READ:

…//接收并显示消息 break;

case FD_CLOSE:

…//输出对方掉线 closesocket(wParam); break;

default:

… }

8、简述WSAEventSelect事件选择模型的编程模型。 答:WSAEventSelect事件选择模型的编程步骤如下: (1)创建事件对象句柄

通过调用WSACreateEvent函数来创建一个对象,该函数的返回值为事件句柄对象句柄。函数原型如下:

WSAEVENT WSACreateEvent(void); 比如:

WSAEVENT newEvent WSACreateEvent(void); (2)关联套接字和事件对象,注册关心的网络事件

通过调用WSAEventSelect函数,把事件对象句柄与套接字关联在一起,同时注册感兴趣的网络事件类型。WSAEventSelect函数的原型为:

int WSAEventSelect( SOCKET s, WSAEVENT hEventObject, long lNetworkEvents); 比如当在套接字s上发生有数据可读或者对方关闭套接字时,向事件对象newEvent传信,则相应的代码为:

WSAEventSelect(s,newEvent,FD_READ | FD_CLOSE); (3)等待网络事件触发事件对象句柄的工作状态

调用WSAWaitForMultipleEvents函数,等待网络事件触发事件对象句柄的工作状态。函数原型如下:

DWORD WSAWaitForMultipleEvents( DWORD cEvents, const WSAEVENT FAR * lphEvents, BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable ); 比如:

Index=WSAWaitForMultipleEvent(1,&newEvent,FALSE,WSA_INFINITE,FALSE);

(4)检查套接字上所发生的网络事件类型

调用WSAEnumNetworkEvents函数,检查出套接字上发生的网络事件类型。函数原型定义如下:

int WSAEnumNetworkEvents( SOCKET s,

WSAEVENT hEventObject,

LPWSANETWORKEVENTS lpNetworkEvents ); 比如:

WSANETWORKEVENTS NetworkEvent;

WSAEnumNetworkEvents(s,newEvent,&NetworkEvent); (5)处理网络事件

确定在套接字上发生的网络事件类型,然后根据不同的情况做出相应的处理。应用程序完成了对一个事件对象的处理后,便应调用WSACloseEvent函数,释放由事件句柄使用的系统资源。比如:

if(NetworkEvent.lNetworkEvent & FD_READ) {

if(NetworkEvent.lErrorCode[FD_READ_BIT] == 0) {

…//接收数据 } else {

…//出错处理 } }

if(NetworkEvent.lNetworkEvent & FD_CLOSE) {

if(NetworkEvent.lErrorCode[FD_CLOSE_BIT] == 0) {

…//关闭连接处理 } else {

…//出错处理 } }

WSACloseEvent(newEvent);

9、编写一个基于数据报套接字的点到点通信程序,具体要求如下:

1) 基于数据报套接字来实现。 2) 服务器方工作的端口号为2000。

3) 客户方通过键盘接收服务器方的IP地址和要发送给服务器方的消息,然后把

该消息发送到服务器方。

4) 服务器方接收客户方的消息并显示,然后产生一条消息并发送给客户方,该

消息的内容是客户方的IP地址、端口号。 5) 客户方接收服务器方响应的消息并显示 6) 双方释放套接字。 答:服务器端代码如下:

#include \#include \

#pragma comment(lib,\int main(int argc, char* argv[]) {

SOCKET sock;

SOCKADDR_IN SerAddr,CliAddr; int alen=sizeof(SOCKADDR_IN); int msglen; char buf[1000]; WORD wVerReq; WSADATA wsaData; wVerReq=MAKEWORD(1,1); if(WSAStartup(wVerReq,&wsaData))

return 1;

memset(&SerAddr,0,alen); SerAddr.sin_family = AF_INET; SerAddr.sin_port = htons(2000);

SerAddr.sin_addr.s_addr=htonl(INADDR_ANY); sock = socket(PF_INET,SOCK_DGRAM,0); bind(sock,(LPSOCKADDR)&SerAddr,alen);

msglen = recvfrom(sock,buf,1000,0,(LPSOCKADDR)&CliAddr,&alen); buf[msglen] = '\\0'; printf(\

sprintf(buf,\sendto(sock,buf,strlen(buf),0,(LPSOCKADDR)&CliAddr,alen); closesocket(sock); WSACleanup(); return 0; }

客户端代码如下:

#include \#include \

#pragma comment(lib,\int main(int argc, char* argv[]) {

SOCKET sock;

SOCKADDR_IN SerAddr;

int alen=sizeof(SOCKADDR_IN); int msglen; char buf[1000]; WORD wVerReq; WSADATA wsaData;

wVerReq=MAKEWORD(1,1);

if(WSAStartup(wVerReq,&wsaData))

return 1;

printf(\请输入服务器的IP地址:\scanf(\

memset(&SerAddr,0,alen);

SerAddr.sin_family = AF_INET; SerAddr.sin_port = htons(2000);

SerAddr.sin_addr.s_addr=inet_addr(buf);

printf(\请输入要发送到服务器的消息:\scanf(\

sock = socket(PF_INET,SOCK_DGRAM,0);

sendto(sock,buf,strlen(buf),0,(LPSOCKADDR)&SerAddr,alen); while((msglen =

recvfrom(sock,buf,1000,0,(LPSOCKADDR)&SerAddr,&alen))<=0) buf[msglen] = '\\0'; printf(\closesocket(sock); WSACleanup(); return 0; }

10、设计一个工作在Windows环境下、基于流式套接字的网络客户端应用程序,要求如下:

1) 基于流式套接字。

2) 服务器端使用的IP地址为:10.132.254.200,端口号是:2000。

3) 客户端连接到服务器端后,把保存在变量msg1中的以’\\0’结尾的字符串发送

到服务器。

4) 服务器端使用printf()函数显示接收到的字符串,然后再把该字符串的长度以

长整型数据的形式发送给客户端。

5) 客户端接收到服务器返回的字符串长度,然后使用printf()函数以“服务器返

回的数据是XXXX”形式输出服务器的返回结果。其中XXXX是服务器返回的数据。

6) 最后服务器和客户均释放连接。

给出能够完成以上功能的服务器端和客户端程序的关键代码。 答:(1)服务器端关键代码如下:

SOCKET sockListen,sockRecv; SOCKADDR_IN SerAddr,CliAddr; WORD wVerReq; WSADATA wsaData;

;

char Buf[1000]; unsigned long int msglen; int alen = sizeof(SOCKADDR); wVerReq = MAKEWORD(1,1); if(WSAStartup(wVerReq,&wsaData))

return;

memset(&SerAddr,0,alen); SerAddr.sin_family = AF_INET; SerAddr.sin_port = htons(2000);

SerAddr.sin_addr.s_addr = htonl(INADDR_ANY);

sockListen=socket(PF_INET,SOCK_STREAM,0); bind(sockListen,(LPSOCKADDR)&SerAddr,alen); listen(sockListen,5); alen = sizeof(SOCKADDR);

sockRecv = accept(sockListen,(LPSOCKADDR)&CliAddr,&alen); msglen = recv(sockRecv, Buf,1000,0); Buf[msglen] = ‘\\0’; printf(\msglen = htonl(msglen);

send(sockRecv,(char *)&msglen, sizeof(msglen), 0); closesocket(sockRecv); closesocket(sockListen); WSACleanup();

(2)客户端关键代码如下:

SOCKET sock;

SOCKADDR_IN SerAddr; WORD wVerReq; WSADATA wsaData;

char msg1[] = %unsigned long int msg2; int alen = sizeof(SOCKADDR); wVerReq = MAKEWORD(1,1); if(WSAStartup(wVerReq,&wsaData))

return;

memset(&SerAddr,0,alen); SerAddr.sin_family = AF_INET; SerAddr.sin_port = htons(2000);

SerAddr.sin_addr.s_addr = inet_addr(\

sock=socket(PF_INET,SOCK_STREAM,0); connect(sock,(LPSOCKADDR)&SerAddr,alen); send(sock,msg1,strlen(msg1),0);

recv(sock,(char *)&msg2,sizeof(unsigned long int),0); msg2 = ntohl(msg2);

printf(\服务器返回的数据是x\\n \closesocket(sock); WSACleanup();

本文来源:https://www.bwwdw.com/article/legx.html

Top