【Stream—7】NetworkStream相关知识分享
一、NetworkStream的作用
和先前的流有所不同,NetworkStream的特殊性可以在它的命名空间中得以了解(System.Net.Sockets),聪明的你马上就会反应过来:既然是在网络中传输的流,那必然有某种协议或者规则约束他,不错,这种协议就是Tcp/Ip协议。这个是什么东西?别急,我先让大家了解以下NetworkStream的作用:如果服务器和客户端之间基于TCP连接的,他们之间能够依靠一个稳定的字节流进行相互传输信息,这也是NetworkStream的最关键的作用,有了这个神奇的协议,NetworkStream便能向其他流一样在网络中(进行点对点的传输),这种传输的效率和速度是非常高的(UDP也很快,稍后再介绍),如果大家对这个概念还不是很清晰的话,别怕,后文中我会更详细的说明。
这里有5点大家先了解以下就行:
1、NetworkStream只能在具有TCP/IP协议之中,如果用在UDP中编译不报错,会报异常。
2、NetworkStream是面向连接的。
3、在网络中利用流的形式传递信息。
4、必须借助Socket(也称之为流式socket),或者使用一些返回的返回值,例如TcpClient类的GetStream方法。
5、用法和普通流方法几乎一模一样,但具有特殊性。
二、简单介绍一下TCP/IP协议和相关层次
提到协议相信许多初学者或者没搞过这块的朋友会一头雾水,不过别怕,协议也是人定的,肯定能搞懂:
其实协议可以这么理解,是人为制定的为某个活动定义的一系列规则和约束,就好比足球比赛的红牌黄牌,这是由世界足联制定的协议或者规范,一旦不按这个协议,足球赛肯定会一片混乱。
进入正题:
TCP/IP
全称:Transmission Control Protocol/Internet Protocol(传输控制协议/因特网互联协议,又名网络通讯协议)
这个便是互联网通信中的最基本协议,tcp/ip定义了电子设备如何进入到互联网,以及数据如何在互联网中传递。既然有了协议,但是空头支票还是不行的,就好比足联制定了这些规则,但是没有裁判在球场上来实施这些规则一样,tcp/ip协议也有它自己的层次结构,关于他的层次结构,大家看图就能明白:
发送数据:
大家不用刻板的取理解这个协议,我还是用我们最普通的浏览网页来给大家讲解一下,首先,打开浏览器输入一个Url,这时候,应用成会判断这个要求是否是http的,然后,http会将请求信息交给传输层来执行,传输层主要负责信息流的格式化并且提供一个可靠的传输,这时候,TCP和UDP这两个协议在这里起作用了,TCP协议规定:接收端必须发回确认,并且加入分组丢失,必须重新发送,接着网络层得到这些需要发送的数据,(网络中的IP协议非常重要,不仅是IP协议,还有ARP协议(查找远程主机MAC地址)),这时候网络层会命令网络接口层取发送这些信息(IP层主要负责的是在节点之间的数据报传送,这里的节点是一台网络设备,比如计算机,大家便可以理解为网络接口层的设备),最终将请求数据发送至远程网站主机后等待远程主机发送来信息。
接收数据:
好了,远程网站主机会根据请求信息(ip,数据报等等)发送一系列的网页数据通过网线或者无线路由,回到网络接口层,然后逐级上报,通过网络层的IP然后通过传输层的一系列格式化,最终通过http返回至浏览器显示网页了。
基于篇幅的关系,还有其他的协议大家可以自行去了解学习,相信园子里很多大神都写过关于http协议的博文,大家也可以去学习一下。
三、简单说明一下TCP和UDP的区别
TCP:
1、TCP是面向连接的通信协议,通过三次握手建立连接
2、TCP提供的是一种可靠的数据流服务,采用“带重传的肯定确认”技术来实现传输的可靠性
UDP:
1、UDP是面向无连接的通信协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送
2、UDP通讯时,不需要接受方确认,属于不可靠传输,可能会出现丢包现象,实际应用中要求在程序员编程验证。
3、由于上述2点的关系,UDP传输速度更快,但是安全性比较差,很容易发生未知的错误,所以本章的NetworkStream无法使用在UDP的功能上。
四、简单介绍下套接字(Socket)的概念
关于Socket的概念和功能可能可以写很长的一篇文章来介绍,这里大家把socket理解tcp/ip协议的抽象,并且能够实现tcp/ip协议栈的工具就行,换句话说,我们可以利用socket实现客户端和服务端双向通信,同样,对于socket最关键的理解还没到位,很多新人或者不常用的朋友会问:socket功能到底时什么?怎么工作的?
再次举个例子,女朋友打电话给我,我可以选择接通或者拒绝,如果我接了她的电话,也就是说,我和她通过电话连接(Connect),那电话就是“Socket”,女友和我都可以时客户端或者服务端,只要点对点就行,我们的声音通过电话传递,但是具体传输内容不归Socket管辖,Socket的直接任务可以归纳为以下几点:
1、创建客户端或服务端
2、服务端或客户端监听是否有服务端或客户端传来的连接信息(Listening)
3、创建点对点连接(Connect)
4、发送accept信息给对方,表示两者已经建立连接,并且可以相互传递信息了(Send)
5、具体发送什么信息内容不是Socket管辖的范围,但是必须是Socket进行发送的动作
6、统里可以通过Socket去接收对方发来的信息,并加以处理
后面我们会简单的写一个Socket的示例
五、简单介绍下TcpClient、TcpListener、IPEndPoint类的作用
1、TcpClient
此类事微软基于Tcp封装类,用于简化Tcp客户端的开发,主要通过构造带入主机地址或者IPEndPoint对象,然后调用Connect进行和服务器点对点的连接,连接成功后通过GetStream方法返回NetworkStream对象。
2、TcpListener
此类也是微软基于Tcp封装类,用于监听服务器或者客户端的连接请求,一旦有连接请求信息,理解交给TcpClient的AcceptTcpClient方法捕获,Start方法用于开始监听。
3、IPEndPoint
处理IP地址和端口的封装类
4、IPAddress
提供包含计算机在IP网络上的地址的工具类
六、使用NetworkStream的注意事项和局限性
从这里开始,才真正的介绍NetworkStream,但前面的一再说明NetworkStream背后那个必须掌握的知识点,这样才能在实际变成过程中很快上手,毕竟NetworkStream的工作环境和其他流有很大的差别,再回到第一节关于NetworkStream的知识点,在使用时有几点必须注意:
1、再次强调NetworkStream是稳定的,面向连接的,所以它只适用TCP协议的环境下工作,所以一旦在UDP环境中,虽然编译不会报错,但是会跳出异常。
2、我们可以通过NetworkStream简化Socket开发
3、如果要建立NetworkStream一个新的实例,则必须使用已经连接的Socket
4、NetworkStream使用后不会自动关闭提供的socket,必须使用NetworkStream构造函数时是定的socket所有权(NetworkStream的构造函数中设置)
5、NetworkStream支持异步读写操作。
NetworkStream的局限性:
1、可惜的是NetworkStream基于安全上的考虑不支持Position属性或Seek方法,寻找或改变流的位置,如果吃土强行使用会报出NotSupport的异常
2、支持传递数据的种类没有直接使用Socket来的多。
七、NetworkStream的构造
1、NetworkStream(Socket socket):
为制定的Scoket创建NetworkStream类的新实例
2、NetworkStream(Socket socket,Boolean ownsSocket):
用来指定Socket所属权为是定的Socket,ownsSocket表示指示NetworkStream是否拥有该Socket
3、NetworkStream(Socket socket,FileAccess fileAccess):
用指定的访问权限为指定的Socket创建FileAccess值得按位组合,这些值指定授予所低通得Scoket上的NetworkStream的访问类型
4、NetworkStream(Socket socket,FileAccess fileAccess,Boolean ownsSocket):
以上就是NetworkStream常用的几个构造
对于NetworkStream构造函数的理解相信大家经过前文的解释也能够掌握了,但是有几点必须强调以下
1、如果用构造产生NetworkStream的实例,则必须使用连接的Socket
2、如果该NetworkStream拥有对Socket的所有权,则在使用NetworkStream的Close方法时,会同时关闭Socket,否则关闭NetworkStream时不会关闭Socket
3、能够创建对指定Socket带有读写权限的NetworkStream
八、NetworkStream的属性
1、CanSeek:用于指示流是否支持查找,它的值始终为false
2、DataAvailable:指示在要读取的NetworkStream上是否有可用的数据,一般来说通过判断这俄格属性来判断NetworkStream是否有数据
3、Length:NetworkStream不支持使用Length属性,强行使用会发生NotSupportedException异常
4、Position:NetworkStream不支持使用Position属性,强行使用会发生NotSupportedException异常
九、NetworkStream的方法
同样,NetworkStream的方法大致重写或继承了Stream的方法,但是以下方法必须注意:
1、int Read(byte[] buffer,int offset,int size)
该方法将数据读入buffer参数并返回成功读取的字节数,如果没有可以读取的数据,则Read方法返回0,Read操作将读取尽可能多的可用数据,直至达到由size参数指定的字节数为止。如果远程主机关闭了连接并且已接受到所有可用数据,Read方法将立即完成并返回0字节。
2、long Seek(long offset,SeekOrigin origin)
将流的当前位置设置为给定值,此方法当前不愁支持,总是引发NotSupportException
3、void Write(byte[] buffer,int offset,int size)
Write方法在指定的offset处启动,并将buffer内容的size字节发送到网络,Write方法将一直处于阻止状态(可以用异步解决),知道发送了请求的字节数或引发SocktException为止,如果收到ScoketException,可以使用SocketException.ErrorCode属性获取特定的错误代码。
十、NetworkStream的简单示例
创建一个客户端向服务端传输图片的小示例
服务端一直监听客户端传来的图片信息
服务端代码:
class Program
{
//全局tcpClient
private static TcpClient _client;
//文件流建立到磁盘上的读写流
static FileStream fs=new FileStream("F:\\abc.jpg",FileMode.Create);
//buffer
private static int bufferlength = ;
private static byte[] buffer = new byte[bufferlength];
//网络流
private static NetworkStream _ns;
static void Main()
{
ConnectAndListen();
// Console.ReadKey();
} static void ConnectAndListen()
{
//服务端监听任何Ip,但是端口号时80的连接
TcpListener listener=new TcpListener(IPAddress.Any,);
//监听对象开始监听
listener.Start();
while (true)
{
Console.WriteLine("等待连接");
//线程会挂在这里,直到客户端发来连接请求
_client = listener.AcceptTcpClient();
Console.WriteLine("已连接");
//得到从客户端传过来的网络流
_ns = _client.GetStream();
//如果网络流中由数据
if (_ns.DataAvailable)
{
//异步读取网络流中的byte信息
_ns.BeginRead(buffer, , bufferlength, ReadAsyncCallBack, null);
}
}
} /// <summary>
/// 异步读取回调函数
/// </summary>
/// <param name="result"></param>
static void ReadAsyncCallBack(IAsyncResult result)
{
int readCount;
//获得每次异步读取数量
readCount = _client.GetStream().EndRead(result);
//如果全部读完退出,垃圾回收
if (readCount<)
{
_client.Close();
_ns.Dispose();
fs.Dispose();
return;
}
//将网络流中的图片数据段顺序写入本地
fs.Write(buffer,,bufferlength);
//再次异步读取
_ns.BeginRead(buffer, , bufferlength, ReadAsyncCallBack, null);
}
}
客户端代码:
class Program
{
static void Main(string[] args)
{
SendImageToServer(@"E:\111.jpg");
} static void SendImageToServer(string imgUrl)
{
if (!File.Exists(imgUrl))
{
return;
}
//创建一个文件流打开图片
FileStream fs = File.Open(imgUrl, FileMode.Open);
//声明一个byte数组接收图片byte信息
byte[] fileBytes = new byte[fs.Length];
using (fs)
{
//将图片byte信息读入byte数组中
fs.Read(fileBytes, , fileBytes.Length);
}
//找到服务器的IP地址
IPAddress address = IPAddress.Parse("127.0.0.1");
//将建TcpClient对象实现与服务器的连接
TcpClient client = new TcpClient();
//连接服务器
client.Connect(address, );
using (client)
{
//连接完服务器后便在客户端和服务器之间产生一个流的通道
NetworkStream ns = client.GetStream();
using (ns)
{
//通过此通道将图片数据吸入网络流,传向服务器接收
ns.Write(fileBytes, , fileBytes.Length);
}
}
}
}
这样就可以通过socket把图片传递过去了。
好了,关于NetworkStream的相关知识就介绍到这里了~
【Stream—7】NetworkStream相关知识分享的更多相关文章
- 【Stream—6】BufferedStream相关知识分享
一.简单介绍以下BufferedStream 在前几章的讲述中,我们已经能够掌握流的基本特性和特点,一般进行对流的处理时,系统肩负着IO所带来的开销,调用十分频繁,这时候就应该想个办法减少这种开销,而 ...
- FileStream相关知识分享
一.如何理解FIleStream 通过前3章的学些,相信大家对于Stream已经有一定的了解,但是又如何去理解FileStream呢?请看下图: 我们磁盘中的任何文件都是通过二进制数组组成,最为直观的 ...
- MemoryStream相关知识分享
一.简单介绍一下MemoryStream MemoryStream是内存流,为系统内存提供读写操作,由于MemoryStream是通过无符号字节数组组成的,可以说MemoryStream的性能可以算比 ...
- StreamWriter 相关知识分享
在介绍StreamWriter之前,我们首先来了解一下它的父类TextWriter. 一.TextWriter 1.TextWriter的构造函数和常用属性方法 下面是TextWriter的构造函数: ...
- XML的相关基础知识分享(二)
前面我们讲了一下XML相关的基础知识(一),下面我们在加深一下,看一下XML高级方面. 一.命名空间 1.命名冲突 XML命名空间提供避免元素冲突的方法. 命名冲突:在XML中,元素名称是由开发者定义 ...
- XML的相关基础知识分享
XML和Json是两种最常用的在网络中数据传输的数据序列化格式,随着时代的变迁,XML序列化用于网络传输也逐渐被Json取代,前几天,单位系统集成开发对接接口时,发现大部分都用的WebService技 ...
- 关于StreamReader的知识分享
今天我们来简单的介绍一下StreamReader,在将StreamReader之前,我们先来了解一下他的父类:TextReader.对于TextReader,大家可能比较陌生,下面我们来看一下Text ...
- listener监听器的相关知识
从别人的博客上我学习了listener的相关知识现在分享给大家 1.概念: 监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上 ...
- 【转】java NIO 相关知识
原文地址:http://www.iteye.com/magazines/132-Java-NIO Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的 ...
随机推荐
- 使用 statcounter 统计 Hexo 博客访问量
介绍 statcounter是一个提供网站访问统计服务的网站: StatCounter is a simple but powerful real-time web analytics service ...
- uni-app 请求封装
1.创建一个http.js const baseUrl = 'http://192.168.1.188:8080'; const httpRequest = (opts, data) => ...
- Spring Cloud ---- 服务注册与发现(Eureka 找到了!找到了! 嘻嘻)
记录一下吧,为什么接触分布式.因为裸辞之后没有找到工作,好的公司都要求有分布式经验,但是我完全没有.在一次面试的时候,面试官说如果你会分布式架构的话,我可以把工资给你开高2.5,我就考虑着给我点时间, ...
- Apache POI使用指南(HSSFWorkbook生成excel)
说 明: 官网:http://poi.apache.org/ 由于poi的功能多样,可以生成ppt.word.excel.......,本文就以生成excel为例进行说明,相信聪明的你一定能举一反三 ...
- 函数基础(二)(day11整理)
目录 昨日内容 函数的定义 函数的三种定义方式 空函数 有参函数 无参函数 函数的调用 函数的返回值 函数的参数 形参 实参 今日内容 可变长参数 可变长形参 可变长实参(仅作了解) 函数对象 函数嵌 ...
- 误删除 mySQL 用户解决办法
误删除用户解决办法 删除用户 删除用户 mysql> truncate mysql.user;Query OK, 0 rows affected (0.05 sec)mysql> sel ...
- Java基础(十六)断言(Assertions)
1.断言的概念 假设确信某个属性符合要求,并且代码的执行依赖于这个属性. 断言机制允许在测试期间向代码插入一些检查语句,当代码发布时,这些插入的检查语句将会被自动地移走. 断言失败是致命的,不可恢复的 ...
- vue条件渲染2
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- super()函数的作用
1.super()调用父类方法,并重写>>>>>>减少代码量(Square类实现) 2.它允许您在子类中调用超类的方法. 这种情况的主要用例是扩展继承方法的功能. ...
- 简述同步和异步,以及js的任务队列.
javascript是单线程的一门语言,所以在执行任务的时候,所有任务必须排队,然后一个一个的执行.这就是同步模式 所以同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个 ...