📄 network.cs
字号:
/*
SignatureData class
--
Stores the signature information. The width and height specify the size of
the signature canvas. The lines property stores a list of line segments.
Each line segment contains an array of points (x and y coordinates).
The class can flatten itself into a stream of bytes and unflatten, or
reconstruct itself, from a stream of bytes. These are used when it needs
to be sent over a TCP socket.
Network class
--
Contains helper methods that read / write data to byte streams and help
with the TCP socket message terminator.
*/
using System;
using System.Text;
using System.Collections;
using System.IO;
using System.Runtime.InteropServices;
using System.Drawing;
namespace Common
{
/// <summary>
/// Class that contains the signature data. The class knows how
/// to flatten itself to a stream of bytes and reconstruct
/// itself from a stream of bytes.
/// </summary>
public class SignatureData
{
// this identifies this class, used when sent over socket
// so receiving application can validate the data stream
static public string SignatureId = "signature";
int _width; // width of signature canvas
int _height; // height of signature canvas
ArrayList _lines; // list of line segments
//
// Properties
//
public ArrayList Lines
{
get { return _lines; }
}
public int Width
{
get { return _width; }
}
public int Height
{
get { return _height; }
}
// construct an object from stream of bytes
public SignatureData(byte[] bits)
{
// index into data stream
int bitsIndex = 0;
// get signature id
if (!IsValidStream(bits, ref bitsIndex))
{
// this is not what we are expecting
throw (new Exception("Invalid data stream."));
}
// width and height
_width = Network.GetInt32(bits, ref bitsIndex);
_height = Network.GetInt32(bits, ref bitsIndex);
// number of line segments
Int32 linesCount = Network.GetInt32(bits, ref bitsIndex);
_lines = new ArrayList(linesCount);
// loop through each line segment and get points
for (int line=0; line < linesCount; line++)
{
// number of points in this segment
Int32 pointsCount = Network.GetInt32(bits, ref bitsIndex);
Point[] points = new Point[pointsCount];
// get all points in this segment
for (int point=0; point < pointsCount; point++)
{
points[point].X = Network.GetInt32(bits, ref bitsIndex);
points[point].Y = Network.GetInt32(bits, ref bitsIndex);
}
// add line segment to list
_lines.Add(points);
}
}
/// <summary>
/// Flatten object to a stream of bytes.
/// </summary>
static public byte[] GetBytes(int width, int height, ArrayList lines)
{
// hold byte stream
MemoryStream stream = new MemoryStream();
// signature id
Network.WriteString(stream, SignatureData.SignatureId);
// width and height
Network.WriteInt32(stream, width);
Network.WriteInt32(stream, height);
// number of segments
Network.WriteInt32(stream, lines.Count);
// each segment
foreach (Point[] points in lines)
{
// points in the segment
Network.WriteInt32(stream, points.Length);
foreach (Point pt in points)
{
Network.WriteInt32(stream, pt.X);
Network.WriteInt32(stream, pt.Y);
}
}
return stream.ToArray();
}
/// <summary>
/// Return true if byte array is a valid SignatureData class,
/// otherwise return false.
/// </summary>
private bool IsValidStream(byte[] bits, ref int bitsIndex)
{
bool valid = false;
// see if first value is length of signature id
Int32 idLength = Network.GetInt32(bits, ref bitsIndex);
if (idLength == SignatureData.SignatureId.Length)
{
// get the signature id mark
byte[] id = Network.GetBytes(bits, ref bitsIndex, idLength);
// see if this is the stream we expect
if (ASCIIEncoding.ASCII.GetString(id, 0, idLength) == SignatureData.SignatureId)
valid = true;
}
return valid;
}
}
/// <summary>
/// Network helper functions.
/// </summary>
public class Network
{
/// <summary>
/// socket message terminator
/// </summary>
static public string Terminator
{
get { return "<data_end>"; }
}
/// <summary>
/// socket message terminator as bytes
/// </summary>
static public byte[] TerminatorBytes
{
get
{
return ASCIIEncoding.ASCII.GetBytes(Terminator);
}
}
// all static methods
private Network()
{
}
/// <summary>
/// Return true if the terminator is located at the
/// end of the byte array, otherwise return false.
/// </summary>
static public bool CheckForTerminator(byte[] data)
{
// return right away if not even long enough to contain terminator
if (data == null || data.Length < Terminator.Length)
return false;
// see if message terminator is at end of stream
string endBuf = Encoding.ASCII.GetString(data,
(int)(data.Length - Terminator.Length), (int)Terminator.Length);
return Network.Terminator.Equals(endBuf);
}
/// <summary>
/// Write int bytes to byte stream.
/// </summary>
static public void WriteInt32(MemoryStream stream, Int32 data)
{
stream.Write(BitConverter.GetBytes(data), 0, Marshal.SizeOf(data));
}
/// <summary>
/// Write string to byte stream. First write length, followed
/// by string content.
/// </summary>
static public void WriteString(MemoryStream stream, string data)
{
// write length of string followed by the string bytes
WriteInt32(stream, data.Length);
stream.Write(ASCIIEncoding.ASCII.GetBytes(data), 0, data.Length);
}
/// <summary>
/// Return int from byte stream.
/// </summary>
static public Int32 GetInt32(byte[] bits, ref int bitsIndex)
{
Int32 data = BitConverter.ToInt32(bits, bitsIndex);
bitsIndex += Marshal.SizeOf(data);
return data;
}
/// <summary>
/// Return specified bytes from byte stream.
/// </summary>
static public byte[] GetBytes(byte[] bits, ref int bitsIndex, int length)
{
byte[] data = new byte[length];
Buffer.BlockCopy(bits, bitsIndex, data, 0, length);
bitsIndex += length;
return data;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -