网络编程实验报告
一实验目的
1了解网络文件传输的方法,学习使用WinSock实现网络文件的传输
2 了解点对点(P2P)网络文件传输的方法,学习使用WinSock实现P2P网络文件的传输。
二实验内容
基于udp协议的文件传输,以及相关代码
三实验步骤
1发送窗口
发送窗口用来对发送端进行流量控制。发送窗口的大小Wt 代表在还没有收到对方确认的条件下,发送端最多可以发送的数据帧的个数。
2接收窗口
接收窗口用来控制接收数据帧。只有当接收到的数据帧的发送序号落在接收窗口内,才允许将该数据帧收下,否则一律丢弃。接收窗口的大小用Wr 来表示,在连续ARQ 协议中,Wr = 1。
在接收窗口和发送窗口间存在着这样的关系:接收窗口发生旋转后,发送窗口才可能向前旋转,接收窗口保持不动时,发送窗口是不会旋转的。这种收发窗口按如此规律顺时钟方向不断旋转的协议就犯法为滑动窗口协议。
发送端的发送线程:
int ret;
int nPacketCount = 0;
DWORD dwRet;
SendBuf sendbuf;
DWORD dwRead;
DWORD dwReadSize;
SendBuf* pushbuf;
//计算一共要读的文件次数,若文件已读完,但客户端没有接收完,
//则要发送的内容不再从文件里读取,而从m_bufqueue 里提取
nPacketCount = m_dwFileSize / sizeof(sendbuf.buf);
//若不能整除,则应加1
if(m_dwFileSize % sizeof(sendbuf.buf) != 0)
++nPacketCount;
SetEvent(m_hEvent);
CHtime htime;
//若已发送大小小于文件大小并且发送窗口前沿等于后沿,则继续发送
//否则退出循环
if(m_dwSend < m_dwFileSize) // 文件没有传输完时才继续传输
{
while(1)
{
dwRet = WaitForSingleObject(m_hEvent, 1000);
if(dwRet == WAIT_FAILED)
{
return false;
}
else if(dwRet == WAIT_TIMEOUT)
{
//重发
::EnterCriticalSection(&m_csQueue); // 进入m_bufqueue 的排斥区
ret = m_hsocket.hsendto((char*)m_bufqueue.front(), sizeof(sendbuf));
::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue 的排斥区
if(ret == SOCKET_ERROR)
{
cout << "重发失败,继续重发" << endl;
continue;
}
ResetEvent(m_hEvent);
continue;
}
//若发送窗口大小 < 预定大小 && 已读文件次数(nReadIndex) < 需要读文件的次数(nReadCoun
t),则继续读取发送
//否则,要发送的内容从m_bufqueue 里提取
if(m_dwSend < m_dwFileSize)
{
dwReadSize = m_dwFileSize - m_dwSend;
dwReadSize = dwReadSize < MAXBUF_SIZE ? dwReadSize : MAXBUF_SIZE;
memset(sendbuf.buf, 0, sizeof(sendbuf.buf));
if(!ReadFile(m_hFile, sendbuf.buf, dwReadSize, &dwRead, NULL))
{
//AfxMessageBox("读取文件失败,请确认文件存在或有读取权限.");
cout << "读取文件失败,请确认文件存在或有读取权限." << endl;
return false;
}
m_dwSend += dwRead;
sendbuf.index = m_nSendIndexHead;
m_nSendIndexHead = (m_nSendIndexHead + 1) % Sliding_Window_Size; // 发送窗口前沿向前移
一格
sendbuf.dwLen = dwRead;
//保存发送过的数据,以便重发
::EnterCriticalSection(&m_csQueue); // 进入m_bufqueue 的排斥区
pushbuf = GetBufFromLookaside();
memcpy(pushbuf, &sendbuf, sizeof(sendbuf));
m_bufqueue.push(pushbuf);
if(m_dwSend >= m_dwFileSize) // 文件已读完,在队列中加一File_End 标志,以便判断是否需
要继续发送
{
pushbuf = GetBufFromLookaside();
pushbuf->index = File_End;
pushbuf->dwLen = File_End;
memset(pushbuf->buf, 0, sizeof(pushbuf->buf));
m_bufqueue.push(pushbuf);
}
::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue 的排斥区
}
::EnterCriticalSection(&m_csQueue); // 进入m_bufqueue 的排斥区
if(m_bufqueue.front()->index == File_End) // 所有数据包已发送完毕,退出循环
{
::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue 的排斥区
break;
}
else if(m_bufqueue.size() <= Send_Window_Size) // 发送窗口小于指定值,继续发送
{
ret = m_hsocket.hsendto((char*)m_bufqueue.front(), sizeof(sendbuf));
if(ret == SOCKET_ERROR)
{
::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue 的排斥区
cout << "发送失败,重发" << endl;
continue;
}
//延时,防止丢包
Sleep(50);
}
else // 发送窗口大于指定值,等持接收线程接收确认消息
{
ResetEvent(m_hEvent);
}
::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue 的排斥区
}
}
发送端的接收线程:
int ret;
RecvBuf recvbuf;
while(m_hFile != NULL)
{
ret = m_hsocket.hrecvfrom((char*)&recvbuf, sizeof(recvbuf));
if(ret == SOCKET_ERROR)
{
//AfxMessageBox("接收确认消息出错");
::EnterCriticalSection(&m_csQueue);
if(m_bufqueue.front()->index == File_End) // 文件传输完毕
{
::LeaveCriticalSection(&m_csQueue);
break;
}
::LeaveCriticalSection(&m_csQueue);
cout << "接收确认消息出错: " << GetLastError() << endl;
return false;
}
if(recvbuf.flag == Flag_Ack && recvbuf.index == m_nSendIndexTail)
{
m_nSendIndexTail = (m_nSendIndexTail + 1) % Sliding_Window_Size;
//该结点已得到确认,将其加入旁视列表,以备再用
::EnterCriticalSection(&m_csQueue);
m_bufLookaside.push(m_bufqueue.front());
m_bufqueue.pop();
::LeaveCriticalSection(&m_csQueue);
SetEvent(m_hEvent);
}
}
接收端的接收线程:
int ret;
DWORD dwWritten;
SendBuf recvbuf;
RecvBuf sendbuf;
int nerror = 0;
// 设置文件指针位置,指向上次已发送的大小
SetFilePointer(m_hFile, 0, NULL, FILE_END);
//若已接收文件大小小于需要接收的大小,则继续
while(m_dwSend < m_dwFileSize)
{
//接收
memset(&recvbuf, 0, sizeof(recvbuf));
ret = m_hsocket.hrecvfrom((char*)&recvbuf, sizeof(recvbuf));
if(ret == SOCKET_ERROR)
{
return false;
}
//不是希望接收的,丢弃,继续接收
if(recvbuf.index != (m_nRecvIndex) % Sliding_Window_Size)
{
nerror++;
cout << recvbuf.index << "error?" << m_nRecvIndex << endl;
continue;
}
if(!WriteFile(m_hFile, recvbuf.buf, recvbuf.dwLen, &dwWritten, NULL))
{
//AfxMessageBox("写入文件失败");
cout << "写入文件失败" << endl;
return false;
}
//已接收文件大小
m_dwSend += dwWritten;
//发送确认消息
sendbuf.flag = Flag_Ack;
sendbuf.index = m_nRecvIndex;
ret = m_hsocket.hsendto((char*)&sendbuf, sizeof(sendbuf));
if(ret == SOCKET_ERROR)
{
return false;
}
//接收窗口前移一格
m_nRecvIndex = (m_nRecvIndex + 1) % Sliding_Window_Size;
}
四实验小结
通过本次的实验,我掌握了基于udp协议实现文件传输的具体内容,也掌握也相关的代码,发送端和接收端的相关知识,udp存在不可靠性,所以用他传输文件,要保证文件不丢失,因为我们要设计相关的代码,从而实现可靠的传输。
第二篇:网络编程技术综合实验报告
辽宁工业大学软件学院
《C#网络编程技术》综合实验报告一
题目: 面向对象程序设计
院(系): 软件学院
专业班级: 软件工程101
学 号: 101301018
学生姓名: 鲁嘉明
指导教师: 翟宝峰
教师职称: 副教授
起止时间:
一、问题描述:
1.理解C#语言是如何体现面向对象编程基本思想。
2.掌握类对象的定义。
3.了解类的封装方法,以及如何创建类和对象。
4.了解成员变量和成员方法的特性。
5.掌握静态成员的用法。
二、问题分析
:
运用所学的类的知识编写一个面向对象的小程序,需要通过程序体现出类的各种属性以及定义方法,要求程序合理并且条例清晰。刚开始我们只需掌握C#基本语法,思想就可以,编写一些简单的C#小程序,使之能运行出来,掌握其中要点,难点,进一步了解面向对象思想,不会时请教老师。
三、程序设计
:
using System;
namespace ConsoleTest
{
class HelloName
{
private string s="张三";
private int i=5;
public HelloName()
{
Console.WriteLine( "hello {0},I have {1} books!",s,i);
}
static void Main(string[] args)
{
int i=1;Console.WriteLine("The first is:{0}",i);
Console.Write("Please enter your name: ");
string strName = Console.ReadLine();
Console.WriteLine("Hello " + strName+" !");
HelloName hello=new HelloName();
hello.i=6;
Console.WriteLine(
"hi {0},I have {1} books!",hello.s,hello.i);
HelloMe me=new HelloMe();me.Welcome();
Console.Read();
}
}
class HelloMe
{
private string s="王五";
private int i=10;
public HelloMe()
{
Console.WriteLine("hello {0},I have {1} books!",s,i);
}
public void Welcome()
{
i=11;
Console.WriteLine( "hi I have {0} books,Welcome to using C#.NET!",i);
}
}
}
四、程序实现:
刚开始编写的程序的时候没有输入Console.WriteLine( "hello {0},I have {1} books!",s,i);忘记了输出的方法结果没能输出结果,后来在同学的帮助下顺利完成。继续下来的时候string strName = Console.ReadLine();不会写内段程序不知道该怎么办了,后来询问同学以及看书寻找发现了问题的所在,当全部编写完成之后还是有错误还是不能运行,后来经过自己仔细的检查以及认真的查找资料后发现了 private string s="王五";private int i=10;public HelloMe(),在类里面添加字符串的时候出现错误,经过改正之后程序可以顺利运行。
利用一周时间老师对我们简单介绍了C#的基本语法,对C#平台有了一个基本介绍,Microsoft .NET 框架是一个平台,它提供了一个多 语言编程环境,同时集成了应用程序和服务,为Internet规模应用程序的部署和操作提供了高度的灵活性。 .NET 框架主要由以下几个主要部分组成:.NET支持的语言、公共语言执行环境(Common Language Runtime)、统一类库的分层集合和ASP.NET。
C#最主要的就是类,面向对象思想,类库是一个由 Microsoft .NET Framework SDK 中 包含的类、接口和值类型组成的库。该库提供对系统功能的访问,是建立 .NET Framework 应用程序、组件和控件的基础。 .NET类库提供了企业级开发所需要的各种功能,完全支持Web标准及其应用,而且使用简单,扩充方便。类库分配到不同的名称空间下,所有名称空间又都归类在System名称空间下。
C#特点有; 1,简洁的语法
2,精心的面向对象设计
3,与Web的紧密结合
4,完全的安全性与错误处理
5,版本处理技术
6,灵活性和兼容性
C#好处有;
1,C#与C++的比较; 编译目标、内存管理、指针、字符串处理、库、继承方式(单、多)。
2,C#与JAVA的比较; 运行环境JRE—CLR,字节码--中间语言。
1. 程序一般包括以下几部分:
? 名称空间的引用:使用using关键字指明引用的名称空间。
? 名称空间的声明:使用namespace关键字声明名称空间。
? 类:使用class关键字声明类。
? Main方法:Main方法是C# 程序的入口。
2. 类中包含了程序所要用到的数据和所要执行的方法的定义。每个类中可以有:
(1)变量声明
(2)构造函数
(3)方法
(4)属性
(5)事件
3. 一个文件中可以有1个或者多个类。
4. 所有语句都以分号";"结束
五、实验总结:
通过本次实验我了解了如何编写面向对象的程序,在试验中我遇到了很多问题才发现自己还有许多东西要去学习,类的定义,类的声明,以及类的参数还有调用问题。学习程序设计的基本目的就是培养我们在实践过程中的自己动手能力,同时在实践中发现自己的不足,自己需要去学习的地方,我们必须把实践跟理论结合在一起,在这次实验之后我会注重实践跟理论的结合同时我会更加努力学好这门课程。