资源描述
《计算机网络与通信》试题
(学术型)
学号 姓名
1. HTTP协议中定义了哪些加密服务?请使用分析http://wiki.wireshark.org/SampleCaptures 中http_with_jpegs.cap.gz A simple capture containing a few JPEG pictures one can reassemble and save to a file. 对话过程。(10分)
(1) SSH服务:为建立在应用层和传输层基础上的安全协议。SSH 是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。
(2) SSL服务:用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络上之传输过程中不会被截取及窃听。
(3) TLS服务:用于在两个通信应用程序之间提供保密性和数据完整性。该协议由两层组成: TLS 记录协议(TLS Record)和 TLS 握手协议(TLS Handshake)。较低的层为 TLS 记录协议,位于某个可靠的传输协议(例如 TCP)上面,与具体的应用无关。
Tcp通过三次握手,建立连接
上图中48、50是向服务器请求.jpg的文件
58、59服务器发送分组后的数据,60客户机回应,61图片发送成功。
2. TCP传输层具有哪些功能?评价传输层性能指标是什么?(10分)
(一)TCP功能:1、完成对数据报的确认、流量控制和网络拥塞;
2、自动检测数据报,并提供错误重发的功能;
3、将多条路径传送的数据报按照原来的顺序进行排列,并对重复数据进行择取;
4、控制超时重发,自动调整超时值;提供自动恢复丢失数据的功能。
(二) 传输层性能指标:1、传输层端到端(TCP)吞吐率.
2、负载:信道或设备在单位时间内所承受的通信流量。
3、转发速率:在某个特定负载下,一台网络设备在单位时间内向目标端口成功转发的帧数。交换机的转发速率与交换机的体系结构、端口带宽、转发模式、设备的负载状况等因素有关。
4、丢帧率:传输过程中丢失的数据帧占应转发帧的比例。
5、突发(Burst):在某个时间段内,一组以合法最小帧间隔传输的以太网帧。
3. 计算机A有一个10G大小文件要通过UDP协议传输给计算机B,请设计文件可靠传输协议(注意考虑断点续传),保证计算机A上的文件可靠传输到计算机B上。(15分)
(一) 将A作为服务器,B作为客户机,进行文件传输。断点续传是基于socket编程实现。
a) 传输起自一个读取或写入文件的请求,这个请求也是连接请求。如果服务器批准此请求,则服务器打开连接,数据以定长512字节传输。
b) 每个数据包包括一块数据,服务器发出下一个数据包以前必须得到客户对上一个数据包的确认(停等协议)。如果一个数据包的大小小于512字节,则表示传输结束。
c) 如果数据包在传输过程中丢失,发出方会在超时后重新传输最后一个未被确认的数据包(丢包处理)。
d) 初始连接时候需要发出WRQ(请求写入)或RRQ(请求读取),收到一个确定应答,一个确定可以写出的包或应该读取的第一块数据。通常确认包包括要确认的包的包号,每个数据包都与一个块号相对应,块号从1开始而且是连续的。因此对于写入请求的确定是一个比较特殊的情况,因此它的包的包号是0。如果收到的包是一个错误的包,则这个请求被拒绝。
e) 在断点续传时,当发送方发出数据包后,网络中断后,无论接受方接收到数据包没有,发送方都不会接收到确认帧,此时发送方会重复的发送未被确认的数据包,接收方也会等待这一个或者下一个数据包的来临。这样故障恢复后,接收方可能会接收到两个相同的数据包(确认帧丢失情况),所以接收会判断接收到的新数据包的编号是否与上一个相同,不相同则写入文件,但无论是否相同,都会发送确认帧,使发送方发送下一个数据包。系统设置了超时结束机制,这与断点续传是一对矛盾。当把超时时间设置的比路由重启的时间和网线滑落手动接上的时间略长就能很好的解决这个矛盾了。
(二)部分源程序
服务器端(SERVER):
主函数部分:
#define _VC
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <winsock.h>
#include <conio.h>
#ifdef _VC
#pragma comment( lib, "Wsock32.lib" )
#endif
#include "makepack.h"
#include "log.h"
#include "time.h"
#include "position.h"
void download(struct sockaddr_in sour_addr,char buffer[]);
void upload(struct sockaddr_in sour_addr,char buffer[]);
SOCKET sock = INVALID_SOCKET;
char desthost[256] = "127.0.0.1"; /*目的主机地址,默认为本机*/
int filemode = TFTP_OCTET; /*发送模式设置为octet*/
int main(int argc, char* argv[])
{
int ret = 0;
sockaddr_in addr;
WSADATA stWSAData;
if(WSAStartup(WSA_VERSION, &stWSAData)!=0){ /*启用winsock*/
printf("Can't start Socket \n");
exit(0);
}
sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); /*#define AF_INET 2 (internetwork: UDP)*/
/*#define SOCK_DGRAM 2(datagram socket)*/
if(sock==INVALID_SOCKET){
printf("Can't create socket \n");
exit(0);
}
/*初始化地址信息*/
addr.sin_family = AF_INET;
addr.sin_port = htons(69);
addr.sin_addr.s_addr = INADDR_ANY;
if(bind(sock,(struct sockaddr *)&addr,sizeof(addr))!=0){
printf("Can't bind socket \n");
exit(0);
}
//初始化远程地址信息
struct sockaddr_in sour_addr;
sour_addr.sin_family = AF_INET;
sour_addr.sin_port = htons(INADDR_ANY);
sour_addr.sin_addr.s_addr = inet_addr(desthost); // IP地址
while(true) {
//定义TFTP首部缓冲区
char recv_buffer[1024] = {0}; // 接收的数据缓冲区
int sour_len = 0;
char *fi=NULL;
fd_set fdr;
FD_ZERO(&fdr);
FD_SET(sock, &fdr);
ret = select(sock, &fdr, NULL,NULL, NULL);
if(SOCKET_ERROR==ret){ /*#define SOCKET_ERROR (-1)*/
printf("Socket error \n");
return 0;
}
else{
if(FD_ISSET(sock,&fdr)){
sour_len = sizeof(sockaddr);
ret = recvfrom(sock,recv_buffer,sizeof(recv_buffer),0,(sockaddr *)&sour_addr,&sour_len);
fi=&recv_buffer[2];
if(recv_buffer[1]==TFTP_RRQ){ //读请求
printf("收到%s下载文件请求\n",inet_ntoa(sour_addr.sin_addr));
record(3,&sour_addr,fi);
download(sour_addr,recv_buffer);
}
if(recv_buffer[1]==TFTP_WRQ){ //写请求
printf("收到%s上传文件请求\n",inet_ntoa(sour_addr.sin_addr));
record(1,&sour_addr,fi);
upload(sour_addr,recv_buffer);
}
}//end if
}//end else
}//end while
return 0;
}
void download(struct sockaddr_in sour_addr,char buffer[])
{
char send_buffer[1024] = {0};
char recv_buffer[1024] = {0};
char data_buffer[1024] = {0};
sockaddr_in dest_addr;
fd_set fdr;
int retry = 0;
int sour_len = 0;
int ret = 0;
int len = 0 ;
int flen = 0;
struct timeval timeout = {10,0};
int stat = TFTP_WSTAT_NEXTACK;
unsigned short lastack= 0;
unsigned short blocknum = 0;
size_t rlen = 0;
FILE *file;
char filename[256]="e:\\source\\";//下载文件位置
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = sour_addr.sin_port;
dest_addr.sin_addr.s_addr = sour_addr.sin_addr.s_addr;
strcat(filename,buffer+2); /*获取文件名,加上路径*/
if((file=fopen(filename,"rb"))==NULL){
printf("File %s not found \n",filename);//
//发送error包
len = makeerr(File_not_found,send_buffer);
sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));
record(5,&sour_addr,filename);
return;
}
rlen = fread(data_buffer,1,512,file); /*读文件*/
flen = flen + rlen;
if(rlen<512 && feof(file)){
stat = TFTP_WSTAT_LASTACK;
}
else{
if(ferror(file)){
fclose(file);
record(5,&sour_addr,filename);
return;
}
}
blocknum++;/*发送第一个数据包,包号为1*/
len = makedata(blocknum,data_buffer,rlen,send_buffer,sizeof(send_buffer));
ret = sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));
locate(csrlin(),10);
printf("%10d byte has sended",flen);
while(true){
FD_ZERO(&fdr);
FD_SET(sock, &fdr);
ret = select(sock, &fdr, NULL,NULL, &timeout);/*检查一或多个 Sockets 是否处于可读状态*/
if(ret==SOCKET_ERROR){
printf("Socket error \n");
fclose(file);
record(5,&sour_addr,filename);
return;
}
else{
if(ret==0){
if(retry==MAX_RETRY){
printf("Time Out \n");
fclose(file);
len = makeerr(Time_out,send_buffer);//超时。发相应的error包
sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));
record(5,&sour_addr,filename);
return;
}
sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));/*重发数据包*/
retry++;
}
else{
retry = 0;
sour_len = sizeof(sockaddr);
ret = recvfrom(sock,recv_buffer,sizeof(recv_buffer),0,(sockaddr *)&sour_addr,&sour_len);
/*接收ACK包*/
if(TFTP_ACK==recv_buffer[1]){
lastack = MAKEWORD(recv_buffer[3],recv_buffer[2]);/*获得ACK的包号*/
switch(stat){
case TFTP_WSTAT_NEXTACK:/*文件没有发送完毕*/
if(blocknum==lastack){/*ACK包与DATA包包号对应*/
rlen = fread(data_buffer,1,512,file);
flen = flen + rlen;
if(rlen<512 && feof(file)){
stat = TFTP_WSTAT_LASTACK;
}
else{
if(ferror(file)){
printf("Error: read file\n");
fclose(file);
//发送error包
len = makeerr(Read_file_Error,send_buffer);
sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));
record(5,&sour_addr,filename);
return;
}
}
blocknum++;
if(blocknum > 65535)
blocknum = 0;
len = makedata(blocknum,data_buffer,rlen,send_buffer,sizeof(send_buffer));
sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));/*发送下一个数据包*/
locate(csrlin(),10);
printf("%10d byte has sended",flen);
}
else{
printf("Error Ack Number.\n");
retry = 0;
sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));/*重发数据包*/
}
break;
case TFTP_WSTAT_LASTACK:
if(lastack==blocknum){
printf("\n传输结束\n");
printf("\ttotal %d byte sended\n",flen);
record(4,&sour_addr,filename);
return;
}
else{
retry = 0;
sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));
printf("Error Ack Number\n");
}
break;
default :
break;
}//end switch
}//end if
}
}
}//end while
}
void upload(struct sockaddr_in sour_addr,char buffer[])
{
char send_buffer[1024] = {0};
char recv_buffer[1024] = {0};
sockaddr_in dest_addr;
struct timeval timeout = {10,0};
int sour_len = 0;
int ret = 0;
int len = 0;
int flen = 0;
int retry = 0;
fd_set fdr;
unsigned short lastdata = 0;
unsigned short blocknum = 0;
FILE *file;
char filename[256]="e:\\source\\";
strcat(filename,buffer+2); /*获取文件名*/
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = sour_addr.sin_port;
dest_addr.sin_addr.s_addr = sour_addr.sin_addr.s_addr;//
if((file=fopen(filename,"rb"))!=NULL){
//发送一个error包,报告存在同名文件
len = makeerr(File_already_exists,send_buffer);
ret = sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));
record(5,&sour_addr,filename);
return;
}
if((file=fopen(filename,"w+b"))==NULL){
printf("Can't create file\n");
//发送error包
len = makeerr(Cannot_create_file,send_buffer);
ret = sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));
record(5,&sour_addr,filename);
return;
}
len = makeack(blocknum,send_buffer,sizeof(send_buffer));
blocknum++;
ret = sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));/*发送WRQ的确认包*/
while(true){
FD_ZERO(&fdr);
FD_SET(sock, &fdr);
ret = select(sock, &fdr, NULL,NULL, &timeout);
if(ret==SOCKET_ERROR){ /*#define SOCKET_ERROR (-1)*/
printf("Socket error \n");
fclose(file);
record(5,&sour_addr,filename);
return;
}
else{
if(ret==0){
if(retry==MAX_RETRY){
printf("Time Out \n");
fclose(file);
record(5,&sour_addr,filename);
return;
}
ret = sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));
retry++;
}
else{
if (FD_ISSET(sock,&fdr)){
retry = 0;
sour_len = sizeof(sockaddr);
ret = recvfrom(sock,recv_buffer,sizeof(recv_buffer),0,(sockaddr *)&sour_addr,&sour_len);
if(recv_buffer[1]==TFTP_DATA){
lastdata = MAKEWORD(recv_buffer[3],recv_buffer[2]);
if(lastdata == blocknum){
len = makeack(blocknum,send_buffer,sizeof(send_buffer));
blocknum++;
if(blocknum > 65535)
blocknum = 0;
sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));
if(ret < TFTP_NOTEND_DATALEN){
fwrite(&recv_buffer[4],1,ret-4,file);
flen = flen + ret -4;
fclose(file);
record(2,&sour_addr,filename);
printf("\n传输结束\n");
printf("\ttotal %d byte received\n",flen);
return;
}
else{
fwrite(&recv_buffer[4],1,512,file);
flen = flen + 512;
locate(csrlin(),10);
printf("%10d byte has received",flen);
}
}//end if(lastdata == blocknum)
else{
printf("Blocknum Error!\n");
sendto(sock,send_buffer,len,0,(sockaddr *)&dest_addr,sizeof(dest_addr));
}
}//end if(TFTP_DATA==recv_buffer[1])
}
}
}
}
}
客户端(CLIENT):
主函数部分:
#define _VC
#include <stdio.h>
#include <winsock.h>
#include <conio.h>
#ifdef _VC
#pragma comment( lib, "Wsock32.lib" )
#endif
#include "cmdfunction.h"
#include "define.h"
#include "cmdprocess.h"
#include "position.h"
SOCKET sock = INVALID_SOCKET; /*#define INVALID_SOCKET (SOCKET)(~0)*/
char desthost[256] = "127.0.0.1"; /*目的主机地址,默认为本机*/
int filemode = TFTP_OCTET; /*发送模式设置为octet,1*/
int main(int argc, char* argv[])
{
char cmd[256];
int ret = 0;
sockaddr_in addr;
WSADATA stWSAData;
if(WSAStartup(WSA_VERSION, &stWSAData)!=0){ /*启用winsock,版本号0101,返回请求的Socket的版本信息*/
printf("Can't start Socket \n");
exit(0);
}
sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); /*#define AF_INET 2 (internetwork: UDP)*/
if(sock==INVALID_SOCKET){
printf("Can't create socket \n");
exit(0);
}
/*初始化地址信息*/
addr.sin_family = AF_INET;
addr.sin_port = htons(INADDR_ANY); /*端口号*/
addr.sin_addr.s_addr = INADDR_ANY; /*IP地址*/
if(bind(sock,(struct sockaddr *)&addr,sizeof(addr))!=0){
printf("Can't bind socket \n");
exit(0);
}
while(true){
fflush( stdin ); /*清空缓冲区*/
printf("-");
gets(cmd); /*接收键盘输入*/
parsecmd(cmd); /*解析输入的命令*/
}
return 0;
}
4. 请使用Bellman-ford算法(提供源码),求出下图中节点A到K的最优路径(15分)。
(一)Bellman-Ford算法描述:
1,.初始化:将除源点外的所有顶点的最短距离估计值 d[v] ←+∞, d[s] ←0;
2.迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;(运行|v|-1次)
3.检验负权回路:判断边集E中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在 d[v]中。
(二)源码
/*
*Bellman-Ford算法
*/
#include <iostream>
using namespace bf;
const int maxnum = 100; //最大顶点数
const int maxint = 100;//大于图中边的任意值,表示无穷大
//定义边
typedef struct Edge{
int u, v; // 起点,重点
int weight; // 边的权值
}Edge;
Edge edge[maxnum]; // 保存边的值
int dist[maxnum]; // 结点到源点最小距离
int nodenum, edgenum, source; // 结点数,边数,源点
//初始化
void init() {
// 输入结点数,边数,源点
cin >> nodenum >> edgenum >> source;
for(int i=1; i<nodenum; ++i) //初始化每点的值d[v] ←+∞
dist[i] = maxint;
dist[source] = 0; // 初始化原点的值d[s] ←0;
for(int i=1; i<=edgenum; ++i) {
cin >> edge[i].u >> edge[i].v >> edge[i].weight;
if(edge[i].u == source) //注意这里设置初始情况 dist[edge[i].v] = edge[i].weight;
} }
//松弛算法
void relax(int u, int v, int weight) {
if(dist[v] > dist[u] + weight)
dist[v] = dist[u] + weight;
}
bool Bellman_Ford() {
for(int i=1; i<=nodenum-1; ++i)
for(int j=1; j<=edgenum; ++j)
relax(edge[j].u, edge[j].v, edge[j].weight);
bool flag = 1;
// 判断是否有负环路
for(int i=1; i<=edgenum; ++i)
if(dist[edge[i].v] > dist[edge[i].u] + edge[i].weight) {
flag = 0;
break;
}
return flag; }
int main() {
init();
if(Bellman_Ford())
for(int i = 1 ;i <= nodenum; i++)
cout << dist[i] << endl;
return 0;
}
得出最优路径为:A—>F—>E—>K
5. 请使用分析http://wiki.wireshark.org/SampleCaptures 中ospf.cap (libpcap) Simple OSPF initialization. 协议对话过程。(10分)
OSPF协议是链路状态路由选择协议,它选择路由的度量标准是带宽,延迟。
(一) OSPF在wireshark中的图如下:
(二) 向本路由器的邻居发送Hello报文,使用组播地址224.0.0.5,制定路由为192.168.170.8,BDR为空,邻居列表为空。
(三) 第二个报文到第七个报文都是如下图:
(四) 第八、九个报文:将对方的router id添加到了active neighbor中,说明hello报文检查通过
(五) 第10个报文,发送空的DBD报文,确定master/slave关系。
(六) 第12个报文:发送带有路由信息的DBD报文,收到后比较自己的数据库
(七) 第17、18报文:路由器开始请求自己需要的数据,发送LSR报文向对方请求所需的LSA.
(八) 路由器开始更新,使用的是224.0.0.5,该地址表示在任意网络中所有运行OSPF进程的接口都属于改组。
(九) 路由器开始更新,使用的是224.0.0.6,该地址指一个多路访问网络中DR和BDR的组播接收地址。
(十) 发送确认报文,需要确认的是LSA的head。
6. 请使用分析http://wiki.wireshark.org/SampleCaptures
展开阅读全文