Socket 中运用 BufferedStream 类(转载)
下面的代码示例演示如何使用 BufferedStream
类,而使用 NetworkStream
类来提高某些 I/O 操作的性能。 在启动客户端之前,在远程计算机上启动服务器。 启动客户端时,将远程计算机名称指定为命令行参数。 dataArraySize
改变 和 streamBufferSize
常量以查看它们对性能的影响。
第一个示例演示在客户端上运行的代码,第二个示例演示在服务器上运行的代码。
示例 1:在客户端上运行的代码
using System; using System.IO; using System.Globalization; using System.Net; using System.Net.Sockets; public class Client { const int dataArraySize = 100; const int streamBufferSize = 1000; const int numberOfLoops = 10000; static void Main(string[] args) { // Check that an argument was specified when the // program was invoked. if(args.Length == 0) { Console.WriteLine("Error: The name of the host computer" + " must be specified when the program is invoked."); return; } string remoteName = args[0]; // Create the underlying socket and connect to the server. Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); clientSocket.Connect(new IPEndPoint( Dns.Resolve(remoteName).AddressList[0], 1800)); Console.WriteLine("Client is connected.\n"); // Create a NetworkStream that owns clientSocket and // then create a BufferedStream on top of the NetworkStream. // Both streams are disposed when execution exits the // using statement. using(Stream netStream = new NetworkStream(clientSocket, true), bufStream = new BufferedStream(netStream, streamBufferSize)) { // Check whether the underlying stream supports seeking. Console.WriteLine("NetworkStream {0} seeking.\n", bufStream.CanSeek ? "supports" : "does not support"); // Send and receive data. if(bufStream.CanWrite) { SendData(netStream, bufStream); } if(bufStream.CanRead) { ReceiveData(netStream, bufStream); } // When bufStream is closed, netStream is in turn // closed, which in turn shuts down the connection // and closes clientSocket. Console.WriteLine("\nShutting down the connection."); bufStream.Close(); } } static void SendData(Stream netStream, Stream bufStream) { DateTime startTime; double networkTime, bufferedTime; // Create random data to send to the server. byte[] dataToSend = new byte[dataArraySize]; new Random().NextBytes(dataToSend); // Send the data using the NetworkStream. Console.WriteLine("Sending data using NetworkStream."); startTime = DateTime.Now; for(int i = 0; i < numberOfLoops; i++) { netStream.Write(dataToSend, 0, dataToSend.Length); } networkTime = (DateTime.Now - startTime).TotalSeconds; Console.WriteLine("{0} bytes sent in {1} seconds.\n", numberOfLoops * dataToSend.Length, networkTime.ToString("F1")); // Send the data using the BufferedStream. Console.WriteLine("Sending data using BufferedStream."); startTime = DateTime.Now; for(int i = 0; i < numberOfLoops; i++) { bufStream.Write(dataToSend, 0, dataToSend.Length); } bufStream.Flush(); bufferedTime = (DateTime.Now - startTime).TotalSeconds; Console.WriteLine("{0} bytes sent in {1} seconds.\n", numberOfLoops * dataToSend.Length, bufferedTime.ToString("F1")); // Print the ratio of write times. Console.WriteLine("Sending data using the buffered " + "network stream was {0} {1} than using the network " + "stream alone.\n", (networkTime/bufferedTime).ToString("P0"), bufferedTime < networkTime ? "faster" : "slower"); } static void ReceiveData(Stream netStream, Stream bufStream) { DateTime startTime; double networkTime, bufferedTime = 0; int bytesReceived = 0; byte[] receivedData = new byte[dataArraySize]; // Receive data using the NetworkStream. Console.WriteLine("Receiving data using NetworkStream."); startTime = DateTime.Now; while(bytesReceived < numberOfLoops * receivedData.Length) { bytesReceived += netStream.Read( receivedData, 0, receivedData.Length); } networkTime = (DateTime.Now - startTime).TotalSeconds; Console.WriteLine("{0} bytes received in {1} seconds.\n", bytesReceived.ToString(), networkTime.ToString("F1")); // Receive data using the BufferedStream. Console.WriteLine("Receiving data using BufferedStream."); bytesReceived = 0; startTime = DateTime.Now; int numBytesToRead = receivedData.Length; while (numBytesToRead > 0) { // Read may return anything from 0 to numBytesToRead. int n = bufStream.Read(receivedData,0, receivedData.Length); // The end of the file is reached. if (n == 0) break; bytesReceived += n; numBytesToRead -= n; } bufferedTime = (DateTime.Now - startTime).TotalSeconds; Console.WriteLine("{0} bytes received in {1} seconds.\n", bytesReceived.ToString(), bufferedTime.ToString("F1")); // Print the ratio of read times. Console.WriteLine("Receiving data using the buffered network" + " stream was {0} {1} than using the network stream alone.", (networkTime/bufferedTime).ToString("P0"), bufferedTime < networkTime ? "faster" : "slower"); } }
示例 2:在服务器上运行的代码
using System; using System.Net; using System.Net.Sockets; public class Server { static void Main() { // This is a Windows Sockets 2 error code. const int WSAETIMEDOUT = 10060; Socket serverSocket; int bytesReceived, totalReceived = 0; byte[] receivedData = new byte[2000000]; // Create random data to send to the client. byte[] dataToSend = new byte[2000000]; new Random().NextBytes(dataToSend); IPAddress ipAddress = Dns.Resolve(Dns.GetHostName()).AddressList[0]; IPEndPoint ipEndpoint = new IPEndPoint(ipAddress, 1800); // Create a socket and listen for incoming connections. using(Socket listenSocket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { listenSocket.Bind(ipEndpoint); listenSocket.Listen(1); // Accept a connection and create a socket to handle it. serverSocket = listenSocket.Accept(); Console.WriteLine("Server is connected.\n"); } try { // Send data to the client. Console.Write("Sending data ... "); int bytesSent = serverSocket.Send( dataToSend, 0, dataToSend.Length, SocketFlags.None); Console.WriteLine("{0} bytes sent.\n", bytesSent.ToString()); // Set the timeout for receiving data to 2 seconds. serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 2000); // Receive data from the client. Console.Write("Receiving data ... "); try { do { bytesReceived = serverSocket.Receive(receivedData, 0, receivedData.Length, SocketFlags.None); totalReceived += bytesReceived; } while(bytesReceived != 0); } catch(SocketException e) { if(e.ErrorCode == WSAETIMEDOUT) { // Data was not received within the given time. // Assume that the transmission has ended. } else { Console.WriteLine("{0}: {1}\n", e.GetType().Name, e.Message); } } finally { Console.WriteLine("{0} bytes received.\n", totalReceived.ToString()); } } finally { serverSocket.Shutdown(SocketShutdown.Both); Console.WriteLine("Connection shut down."); serverSocket.Close(); } } }
注解
缓冲区是内存中用于缓存数据的字节块,从而减少对操作系统的调用次数。 缓冲区可提高读取和写入性能。 缓冲区可用于读取或写入,但绝不能同时用于两者。 的 ReadBufferedStream
和 Write 方法会自动维护缓冲区。
重要
此类型实现 IDisposable 接口。 在使用完类型后,您应直接或间接释放类型。 若要直接释放类型,请在 try
/catch
块中调用其 Dispose 方法。 若要间接释放类型,请使用 using
(在 C# 中)或 Using
(在 Visual Basic 中)等语言构造。 有关详细信息,请参阅 IDisposable 接口主题中的“使用实现 IDisposable 的对象”一节。
BufferedStream
可以围绕某些类型的流组成。 它提供用于在基础数据源或存储库中读取和写入字节的实现。 使用 BinaryReader 和 BinaryWriter 读取和写入其他数据类型。 BufferedStream
旨在防止缓冲区在不需要缓冲区时减慢输入和输出。 如果始终读取和写入大于内部缓冲区大小的大小,则 BufferedStream
甚至可能不分配内部缓冲区。 BufferedStream
还缓冲共享缓冲区中的读取和写入操作。 假设你几乎总是执行一系列读取或写入操作,但很少在两者之间交替。
原文地址:
BufferedStream 类 (System.IO) | Microsoft Learn
posted on 2023-03-17 17:22 wangzhiliang 阅读(27) 评论(0) 编辑 收藏 举报