Visual C#.Net网络程序开发-Tcp篇(2) 祥细内容:

简介: 前面我们说,TcpClient类创建在Socket之上,在Tcp服务方面提供了更高层次的抽象,体现在网络数据的发送和接受方面,是TcpClient使用标准的Stream流处理技术,使得它读写数据更加方便直观,同时,.Net框架负责提供更丰富的结构来处理流,贯穿于整个.Net框架中的流具有更广泛的兼容性,构建在更一般化的流操作上的通用方法使我们不再需要困惑于文件的实际内容(HTML、XML 或其他任何内容),应用程序都将使用一致的方法(Stream.Write、Stream.Read) 发送和接收数据。
前面我们说,TcpClient类创建在Socket之上,在Tcp服务方面提供了更高层次的抽象,体现在网络数据的发送和接受方面,是TcpClient使用标准的Stream流处理技术,使得它读写数据更加方便直观,同时,.Net框架负责提供更丰富的结构来处理流,贯穿于整个.Net框架中的流具有更广泛的兼容性,构建在更一般化的流操作上的通用方法使我们不再需要困惑于文件的实际内容(HTML、XML 或其他任何内容),应用程序都将使用一致的方法(Stream.Write、Stream.Read) 发送和接收数据。另外,流在数据从 Internet 下载的过程中提供对数据的即时访问,可以在部分数据到达时立即开始处理,而不需要等待应用程序下载完整个数据集。.Net中通过NetworkStream类实现了这些处理技术。
  
  NetworkStream 类包含在.Net框架的System.Net.Sockets 命名空间里,该类专门提供用于网络访问的基础数据流。NetworkStream 实现通过网络套接字发送和接收数据的标准.Net 框架流机制。NetworkStream 支持对网络数据流的同步和异步访问。NetworkStream 从 Stream 继承,后者提供了一组丰富的用于方便网络通讯的方法和属性。
  
  同其它继承自抽象基类Stream的所有流一样,NetworkStream网络流也可以被视为一个数据通道,架设在数据来源端(客户Client)和接收端(服务Server)之间,而后的数据读取及写入均针对这个通道来进行。
  
  .Net框架中,NetworkStream流支持两方面的操作:
  
  1、 写入流。写入是从数据结构到流的数据传输。
  
  示 意 图
  
   15632.gif
  2、读取流。读取是从流到数据结构(如字节数组)的数据传输。
  
  示 意 图
   15633.gif
  与普通流Stream不同的是,网络流没有当前位置的统一概念,因此不支持查找和对数据流的随机访问。相应属性CanSeek 始终返回 false,而 Seek 和 Position 方法也将引发 NotSupportedException。
  
  基于Socket上的应用协议方面,你可以通过以下两种方式获取NetworkStream网络数据流:
  
  1、使用NetworkStream构造函数:public NetworkStream(Socket, FileAccess, bool);(有重载方法),它用指定的访问权限和指定的 Socket 所属权为指定的 Socket 创建 NetworkStream 类的新实例,使用前你需要创建Socket对象实例,并通过Socket.Connect方法建立与远程服务端的连接,而后才可以使用该方法得到网络传输流。示例如下:
  
  Socket s=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//创建客户端Socket对象实例
   try{
   s.Connect("www.tuha.net",4088);//建立与远程主机的连接
   }
   catch(Exception e){
   MessageBox.show("连接错误:" +e.Message);
   }
   try{
   NetworkStream stream=new NetworkStream(s,FileAccess.ReadWrite,false);//取得网络传输流
   }
  
  
  2、通过TcpClient.GetStream方法:public NetworkStream etStream();它返回用于发送和接收数据的基础网络流NetworkStream。GetStream 通过将基础 Socket 用作它的构造函数参数来创建 NetworkStream 类的实例。使用前你需要先创TcpClient对象实例并建立与远程主机的连接,示例如下:
  
  TcpClient tcpClient = new TcpClient();//创建TcpClient对象实例
   Try{
   tcpClient.Connect("www.tuha.net",4088);//尝试与远程主机相连
   }
   catch(Exception e){
   MessageBox.Show("连接错误:"+e.Message);
   }
   try{
   NetworkStream stream=tcpClient.GetStream();//获取网络传输流
   }
   catch(Exception e)
   {
   MessageBox.Show("TcpClient错误:"+e.Message);
   }
  
  
  通过以上方法得到NetworkStream网络流之后,你就可以使用标准流读写方法Write和Read来发送和接受数据了。
  
  以上是.Net下使用TcpClient类实现客户端编程的技术资料,为了向客户端提供这些服务,我们还需要编制相应的服务端程序,前一篇《Visual C#.Net网络程序开发-Socket篇》上曾经提到, Socket作为其他网络协议的基础,既可以面向客户端开发,也可以面向服务端开发,在传输层面上使用较多,而在应用协议层面上,客户端我们采用构建于Socket类之上的TcpClient取代Socket;相应地,构建于Socket之上的TcpListener提供了更高理念级别的 TCP 服务,使得我们能更方便地编写服务端应用程序。正是因为这样的原因,像FTP 和 HTTP 这样的应用层协议都是在 TcpListener 类的基础上建立的。
  
  .Net中的TCPListener 用于监视TCP 端口上的传入请求,通过绑定本机IP地址和相应端口(这两者应与客户端的请求一致)创建TcpListener对象实例,并由Start方法启动侦听;当TcpListener侦听到用户端的连接后,视客户端的不同请求方式,通过AcceptTcpClient 方法接受传入的连接请求并创建 TcpClient 以处理请求,或者通过AcceptSocket 方法接受传入的连接请求并创建 Socket 以处理请求。最后,你需要使用 Stop 关闭用于侦听传入连接的 Socket,你必须也关闭从 AcceptSocket 或 AcceptTcpClient 返回的任何实例。这个过程详细解说如下:
  
  首先,创建TcpListener对象实例,这通过TcpListener类的构造方法来实现:
  
  public TcpListener(port);//指定本机端口
  public TcpListener(IPEndPoint)//指定本机终结点
  public TcpListener(IPAddress,port)//指定本机IP地址及端口
  
  
  以上方法中的参数在前面多次提到,这里不再细述,唯一需要提醒的是,这些参数均针对服务端主机。下面的示例演示创建 TcpListener 类的实例:
  
  IPHostEntry ipInfo=Dns.Resolve("127.0.0.1");//主机信息
   IPAddressList[] ipList=ipInfo.IPAddressList;//IP数组
   IPAddress ip=ipList[0];//IP
   try{
   TcpListener tcpListener = new TcpListener(ipAddress, 4088);//创建TcpListener对象实例以侦听用户端连接
   }
   catch ( Exception e){
   MessageBox.Show("TcpListener错误:"+e.Message);
   }
  
  
  随后,你需要调用Start方法启动侦听:
  
  public void Start();
  
  
  其次,当侦听到有用户端连接时,需要接受挂起的连接请求,这通过调用以下两方法之一来完成连接:
  
  public Socket AcceptSocket();
  public TcpClient AcceptTcpClient();
  
  
  前一个方法返回代表客户端的Socket对象,随后可以通过Socket 类的 Send 和 Receive 方法与远程计算机通讯;后一个方法返回代表客户端的TcpClient对象,随后使用上面介绍的 TcpClient.GetStream 方法获取 TcpClient 的基础网络流 NetworkStream,并使用流读写Read/Write方法与远程计算机通讯。
  
  最后,请记住关闭侦听器:public void Stop();
  
  同时关闭其他连接实例:public void Close();
  
  下面的示例完整体现了上面的过程:
  
  bool done = false;
   TcpListener listener = new TcpListener(13);// 创建TcpListener对象实例(13号端口提供时间服务)
   listener.Start();//启动侦听
   while (!done) {//进入无限循环以侦听用户连接
   TcpClient client = listener.AcceptTcpClient();//侦听到连接后创建客户端连接TcpClient
   NetworkStream ns = client.GetStream();//得到网络传输流
   byte[] byteTime = Encoding.ASCII.GetBytes(DateTime.Now.ToString());//预发送的内容(此为服务端时间)转换为字节数组以便写入流
   try {
   ns.Write(byteTime, 0, byteTime.Length);//写入流
   ns.Close();//关闭流
   client.Close();//关闭客户端连接
   }
  catch (Exception e) {
   MessageBox.Show("流错误:"+e.Message)
   } 
  
相关文章
|
18天前
|
数据可视化 网络协议 C#
C#/.NET/.NET Core优秀项目和框架2024年3月简报
公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯🔔)。
|
1月前
|
SQL 数据库 C#
C# .NET面试系列十一:数据库SQL查询(附建表语句)
#### 第1题 用一条 SQL 语句 查询出每门课都大于80 分的学生姓名 建表语句: ```sql create table tableA ( name varchar(10), kecheng varchar(10), fenshu int(11) ) DEFAULT CHARSET = 'utf8'; ``` 插入数据 ```sql insert into tableA values ('张三', '语文', 81); insert into tableA values ('张三', '数学', 75); insert into tableA values ('李四',
66 2
C# .NET面试系列十一:数据库SQL查询(附建表语句)
|
1月前
|
开发框架 算法 搜索推荐
C# .NET面试系列九:常见的算法
#### 1. 求质数 ```c# // 判断一个数是否为质数的方法 public static bool IsPrime(int number) { if (number < 2) { return false; } for (int i = 2; i <= Math.Sqrt(number); i++) { if (number % i == 0) { return false; } } return true; } class Progr
58 1
|
1月前
|
并行计算 安全 Java
C# .NET面试系列四:多线程
<h2>多线程 #### 1. 根据线程安全的相关知识,分析以下代码,当调用 test 方法时 i > 10 时是否会引起死锁? 并简要说明理由。 ```c# public void test(int i) { lock(this) { if (i > 10) { i--; test(i); } } } ``` 在给定的代码中,不会发生死锁。死锁通常是由于两个或多个线程互相等待对方释放锁而无法继续执行的情况。在这个代码中,只有一个线程持有锁,且没有其他线程参与,因此不
105 3
|
4天前
|
机器学习/深度学习 存储 计算机视觉
r语言中对LASSO回归,Ridge岭回归和弹性网络Elastic Net模型实现-4
r语言中对LASSO回归,Ridge岭回归和弹性网络Elastic Net模型实现
35 11
|
4天前
|
机器学习/深度学习 算法 数据可视化
r语言中对LASSO回归,Ridge岭回归和弹性网络Elastic Net模型实现-3
r语言中对LASSO回归,Ridge岭回归和弹性网络Elastic Net模型实现
12 0
|
4天前
|
算法 数据可视化
r语言中对LASSO回归,Ridge岭回归和弹性网络Elastic Net模型实现-1
r语言中对LASSO回归,Ridge岭回归和弹性网络Elastic Net模型实现
18 0
|
11天前
|
开发框架 前端开发 JavaScript
采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示
技术架构:Asp.NET CORE 3.1 MVC + SQLserver + Redis等 开发语言:C# 6.0、JavaScript 前端框架:JQuery、EasyUI、Bootstrap 后端框架:MVC、SQLSugar等 数 据 库:SQLserver 2012
|
1月前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(持续更新)
C#/.NET/.NET Core拾遗补漏合集(持续更新)
|
1月前
|
SQL 存储 关系型数据库
C# .NET面试系列十:数据库概念知识
#### 1. 为什么要一定要设置主键? 设置主键是数据库设计中的一个重要概念,有几个主要原因: 1、唯一性 ```c# 主键必须保证表中的每一行都有唯一的标识。这样可以避免数据冗余和不一致性。如果没有主键或者主键不唯一,就可能出现数据混乱或错误。 ``` 2、查询性能 ```c# 数据库系统通常会使用主键来加速数据检索。主键通常会被索引,这样可以更快速地找到特定行的数据,提高查询效率。 ``` 3、关联性 ```c# 主键常常用于建立表与表之间的关系。在关系数据库中,一个表的主键通常与其他表中的外键建立关联,这种关系对于数据的一致性和完整性非常重要。 ``` 4、数据完
131 1
C# .NET面试系列十:数据库概念知识