网络流、网络数据的编解码(C#---网络编程)

网络流、网络数据的编解码(C#---网络编程)


一、网络流

当通过网络传输数据或对文件数据进行操作时,需要将数据转化为数据流的形式。数据流(Stream)是对串行传输的数据(以字节为单位)的一种抽象表示,数据源可以是文件、外部设备、主存、网络套接字等。数据流分为文件流、内存流和网络流3种类型。其中,网络流用于在网络上传输数据。在使用网络流时,数据在网络的各个位置之间以连续的字节形式传输。C#在System.Net.Sockets命名空间中提供了NetworkStream类用于收发网络数据。


NetworkStream类只支持面向连接的套接字,对NetworkStream流,写入操作是从源端内存缓冲区到网络上的数据传输,读取操作是从网络上到目的端内存缓冲区的数据传输。


1、获取NetworkStream实例

在构造一个NetworkStream实例后,就可以用它来收发网络数据。

(1)利用TcpClient获取网络流对象

	TcpClient  tcpClient=new TcpClient();
	tcpClient.Connect("www.fzu.edu.cn",5188);
	NetworkStream  myNetworkStream=tcpClient.GetStream();

(2)利用Socket获取网络流对象

	NetworkStream myNetworkStream=new NetworkStream(mySocket);	//myScoket为获取的Socket对象

(3)利用NetworkStream实例收发数据


Write方法负责将字节数组从进程缓冲区发送到本机的TCP缓冲区,然后TCP/IP协议栈通过网络适配器将数据真正发送到网络上,最终到达接收方的TCP接收缓冲区。

由于Write方法为同步方法,所以在发送成功或者返回异常前都处于阻塞状态,直到发送成功或者返回异常。

示例1.使用NetworkStream发送数据

	if(myNetworkStream.Canwrite)
	{
		byte[] myWriteBuffer=Encoding.ASCII.GetBytes("Are you receiving this message?");
		myNetworkStream.Write(myWriteBuffer,0,myWriteBuffer.Length);
	}
	else
		Console.WriteLine("Sorry.You cannot  write to this NetworkStream.");

示例2.使用NetworkStream读取数据

if(myNetworkStream.CanRead)
{
	byte[]  myReadBuffer=new byte[1024];
	String myCompleteMessage="";
	int numberOfBytesRead=0;
	//准备接收的信息有可能大于1024,所以用循环
	do
	{
		numberOfBytesRead=myNetworkStream.Read(myReadBuffer,0,myReadBuffer.Length);
		myCompleteMessage=String.Concat(myCompleteMessage,Encoding.ASCII.GetString(myReadBuffer,0,numberOfBytesRead));
		
	}while(myNetworkStream.DataAvailable);
}

二、网络数据的编码与解码

1、常用字符编码方式

(1)ASCII字符集

(2)非ASCII字符集:我国常用的标准GB2312和GB18030-2000编码。

(3)Unicode字符集

C#的默认字符都是Unicode码,一个英文和一个汉字一样,都占2个字节。

  • UTF-8:是一种针对Unicode的可变长度字符编码。UTF-8用1到4个字节编码Unicode字符
  • UTF-16
  • UTF-32
2、C#中的编码与解码类

(1)Encoding类

Encoding类位于System.Text命名空间中,主要用于在不同的编码和Unicode之间进行转换。


利用Convert方法将字节数组从一种编码转换为另一种编码,其方法原型:

		public  static  byte[]  Convert(Encoding  srcEncoding,Encoding  dstEncoding,byte[] bytes);

返回值:包含转换结果的byte类型的数组。

参数:

  • srcEncoding:表示源编码格式。
  • dstEncoding:表示目标编码格式。
  • bytes:为待转换的字节数组。

在将Unicode字符串转换为UTF-8字符串的步骤:

  • (1)利用Encoding的UTF-8和Unicode属性获取UTF-8格式的编码实例utf8和Unicode编码实例unicode,如:

		string unicodeString="unicode字符串pi(\u03a0)";
		Encoding unicode=Encoding.Unicode;
		Encoding utf8=Encoding.UTF8;

  • (2)利用unicode实例的GetBytes方法将Unicode字符编码为Unicode字节数组:

		byte[]  unicodeBytes=unicode.GetBytes(unicodeString);

  • (3)利用Encoding的Convert方法将Unicode字节数组转换为UTF-8字符串:

		byte[] utf8Bytes=Encoding.Convert(Encoding.Unicode,Encoding.UTF8,unicodeBytes);

  • (4)利用实例utf8的GetString方法将UTF-8字节数组解码为UTF-8字符串:

		string  utf8String=utf8.GetString(utf8Bytes);

(2)Encoder类和Decoder类

在网络传输和文件操作中,如果数据量比较大,需要将其划分为较小的块,对于跨块传输的情况直接使用Encoding类的GetBytes方法编程比较麻烦,而Encoder和Decoder由于维护了数据块的结尾信息,可以轻松实现。

Encoder可以将一组字符串转换为一个字节序列。

Decoder则将已编码的字节序列解码为字符序列。

Encoder编码步骤:

(1)获取Encoder实例。由于Encoder的构造函数为protected,不能直接创建该类的实例,必须通过Encoding提供的GetEncoder方法创建实例:

	//获取ASCII编码的Encoder实例
	Encoder  ASCiiEncoder=Encoding.ASCII.GetEncoder();
	//获取Unicode编码的Encoder实例
	Encoder  unicodeEncoder=Encoding.Unicode.GetEncoder();

(2)GetBytes方法。获取Encoder实例后,利用它的GetBytes方法将一字符编码转换为字节序列:

方法原型:

public  virtual int GetBytes(
		char []  chars,	//要编码的字符数组
		char Index,		//第一个要编码的字符索引
		int charCount,		//要编码的字符的数目
		byte[]  bytes,		//存储编码后的字节序列
		int byteIndex,		//开始写入所产生的字节序列的索引位置
		bool  flush		//是否在转换后清除编码器的内部状态
);

(3)GetByteCount方法。该方法计算对字符序列进行编码后所产生的精确字节数,以确定GetBytes方法中byte类型数组实例的长度。

方法原型

public  abstract int GetByteCount(
		char[]  chars,		//要编码的字符集的字符数组
		int index,		//第一个要编码的字符索引
		int count,		//要编码的字符的数目
		bool  flush		//是否在转换后清除编码器的内部状态
);


Decoder解码步骤:

首先通过Encoding的GetDecoder方法创建Decoder实例,然后用实例的GetChars方法将字节序列解码为一组字符。

GetChars方法用于将一个字节序列解码为一组字符,并从指定的索引位置开始存储这组字符。

方法原型:

public  abstract  int GetChars(
			byte[] bytes,		//要解码的字符序列的字符数组
			int byteIndex,		//第一个要解码的字节的索引
			int byteCount,		//要解码的字符的数目
			char[]  chars,		//包含所产生的字符集的字符数组
			int charIndex		//开始写入所产生的字符集的字节数组的索引位置
);

该方法返回值:chars写入的实际字符数。


示例.利用Encoder类和Decoder类实现编码和解码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Encoder_Decoder
{
    class Program
    {
        static void Main(string[] args)
        {
            //Encoder
            string test = "ABCDE1234测试";
            Console.WriteLine("The test of string is:{0}", test);
            Encoding encoding = Encoding.UTF8;
            char[] source = test.ToCharArray();
            int strLength = test.Length;
            int len = encoding.GetEncoder().GetByteCount(source, 0, strLength, false);
            byte[] result = new byte[len];
            encoding.GetEncoder().GetBytes(source, 0, strLength, result, 0, false);
            Console.WriteLine("After Encoder,the byte of test is output below.");
            foreach (byte b in result)
            {
                Console.Write("{0:X}-", b);

            }
            Console.WriteLine();

            //Decoder
            Console.Write("After Decoder,the string is");
            int deslen = encoding.GetDecoder().GetCharCount(result, 0, result.Length);

            char[] des = new char[deslen];
            encoding.GetDecoder().GetChars(result, 0, result.Length, des, 0);
            foreach (char c in des)
            {
                Console.Write("{0}", c);
            }
            Console.WriteLine("\n");
        }
    }
}

运行结果


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值