/// *
Title: Use asynchronous socket to program the communication architecture of the C / S of the TCP network service in C # (1) ---- Basic Class Bank section
When I saw TCPLISTENER and TCPCPClient, I was very happy, that is, I want's communication mode but found that their power is too thin, we need a better class library to replace them.
Below, some classes are provided, which can complete TCP C / S communication mode. In the second part of this article, I will introduce you how to use them.
Mainly through events, the entire function: the server's events include:
The events that the server fully new client connection client shuts down the receipt of the data client includes:
The connected server receives the data connection to close
In addition, in order to flexibly handle demand changes, it also provides a method of implementation of encoders and packet parsers. Note: This class has not been tested by strict testing, if a bug, please send it to me, I will feel that your entire behavior is Encourage and support for me.
* ///
/// /// (c) 2003-2005 C2217 Studio /// Reserved // // file name: tcpcsframework.cs /// file ID: /// programming language: c # // / Document Description: Communication framework base class /// (using an asynchronous socket programming implementation) /// // Current version: 1.0 ////// author: Deng Yang were /// EMail: dyj057@gmail.com/// creation date: 2005-3-9 /// last modified: 2005-3-17 /// /// history records: // / /// Time: 2005-3-14 // / Modified Content: /// 1. Create IBMS.NET.TCPCSFramework Namespace and Add Session Object ./// 2. Modify the NetEventargs class to accommodate new add objects. /// 3. Added a session exit type, more suitable for the actual situation ./// Note: /// * Forced exit type is the direct end of the application, such as end ////rries or programs to exit by the task manager, etc. No normal exit method is generated ./// * Normal exit type is the key to the application execution of normal exit, and then call Socket.ShutDown (SocketShutDown.both) to call /// Socket .Close () method, not directly call socket.close () method, // if that call will produce a forced exit type. / / / / / / / / // 1. Create TCPCLI, CODER, DataGramResover objects, separated abstract and implementation part //// / 2. File version is modified to 1.1,1.0 is still retained, renamed: /// tcpcsframework_v1.0.cs //// 3. Modify custom HashTable in TCPServer is system HashTable Type // / / / / summary>
Using system.net.sockets; using system.net; using system.diagnostics; using system.collections;
Namespace ibms.net.tcpcsframework {
/// /// network communication event model commission /// summary> public delegate void NetEvent (Object sender, NetEventArgs e); /// /// Provides a server class / // /// version: 1.1 /// Replace version: 1.0 // /// Features: /// 1. Use the Hash table to save all the status of the connected client, you can achieve quick lookup when you receive the data. Whenever /// There is a new session that will generate a new session. This session represents a passenger ///-house object. /// 2. Use asynchronous Socket events as the foundation, complete the network communication function . /// 3. Support for identification of tagged data packets to complete the transmission of big data packets and adapt to bad networks /////////////bit environment, initially stipulate the maximum data packet supported by this class (ie The size of a packet cannot be greater than ///640K, otherwise the server program will automatically delete the packet data, and it is considered to be illegal data) to prevent the server crash because of the data packet /// unlimited growth. // 4. Format The encoding.default format can be used by default. You can /// // /// /// ////// ///// ///-8 communication method of U-16 and U-8 can also be used. You can inherit the //// inheritance class The medium load encoding and decoding functions, custom encryption formats are communicating. In summary, the client and service /// server use the same communication format /// 5. Use C # Native Code, future considerations can be considered in efficiency Can C The 32-bit DLL written by the code is instead /// c # core code, but does this lack of portability, and is the unsafe code (the C code of this class also exists) /// 6. The number of maximum login clients that can limit the server /// 7. With more fine control and more powerful asynchronous data transfer than using TCPListener, it can be used as an alternate class /// 8 for // TCPListener, using asynchronous communication mode, completely do not worry about communication blocking and thread problems, No need to consider the details of communication ///// Note: /// 1. The part of the code is generated by the Rational XDE, possibly with the coding specification /// /// Principle: // / / / / //////// Use usage : // /// Example: ///// summary> public class tcpsvr {#R EGION Definition Field /// /// The default server maximum connection client data /// summary> public const in defaultmaxclient = 100; /// /// Receive data buffer size 64K /// summary> public const Int defaultBuffersize = 64 * 1024;
/// /// Maximum data packet size /// summary> public const Int maxdatagramsize = 640 * 1024;
/// /// packet parser /// summary> private damramresolver_resolver;
/// /// Communication format codec /// summary> private coder _coder;
/// /// server program used port /// summary> private usort _port;
/// /// server program allowed maximum client connections /// summary> private ushort _maxclient;
/// /// server running status /// summary> private bool _srun; /// /// Receive data buffer /// summary> private byte [] _recvdataBuffer;
/// /// server uses asynchronous socket classes, /// summary> private socket _svrsock;
/// /// Save all client sessions /// /////////////////////////////////////////////////////////////////////////////////////////////////////>;;
/// /// The number of clients currently connected /// summary> private ushort _clientcount;
#ndregion
#REGON event definition /// /// Client Establish connection event /// summary> public event NetEvent ClientConn;
/// /// Client Close Event /// summary> public evenet NetEvent ClientClose;
/// /// server is full of events /// summary> public event NetEvent ServerFull;
/// /// server receives data event /// summary> public evenet NetEvent Recvdata;
#endregion #Region constructor
/// /// Structure /// summary> /// server-side port number param> /// The server can accommodate the maximum capabilities of the client param> /// Communication code param> public tcpsvr (ushort port, ushort maxclient, coder code) {_port = port; _maxclient = maxclient ; _CODER = CODER;}
/// /// Constructor (default use default encoding mode) /// summary> /// server-side port number param> /// < param name = "maxClient"> the server can accommodate the maximum capabilities of the client's param> public TcpSvr (ushort port, ushort maxClient) {_port = port; _maxClient = maxClient; _coder = new Coder (Coder.EncodingMothord.Default);}
// /// Constructor (default use default encoding method and defaultmaxclient (100) client capacity) /// summary> /// server-side port number param> Public TCPSVR (Ushort Port): this (port, defaultmaxclient) {} #ENDREGON
#region attribute
/// /// server Socket object /// summary> public socket serversocket {get {return_svrsock;}}
/// /// Data Packet Analyzer /// summary> Public DataGramresolver resovlver {get {return_resolver;} set {_resolver = value;}}
/// /// client session array, save all clients, do not allow the content of the array /// summary> public hashtable sessionTable {Get {Return_SessionTableTable;}}
/// /// server can accommodate the maximum capabilities of the client /// summary> public int Capacity {get {return_maxclient;}}
/// /// Current client connection number /// summary> public int sessioncount {get {return_clientcount;}}
/// // / server running status /// summary> public bool isrun {get {return_ismun;}}
#endregion #Region public method
/// /// Start the server program, start listening to the client request /// summary> public virtual void start () {if (_ _RUN) {throw ("TCPSVR is already running.") );} _SessionTable = new hashtable (53); _RECVDATABUFFER = New byte [defaultBuffersize];
// Initialize Socket_svrsock = New Socket (AddressFamily.internetwork, Sockettype.Stream, ProtocolType.tcp);
// Bind port IpendPoint IEP = New IpendPoint (ipaddress.any, _port); _svrsock.bind (IEP);
// Start listening _SVRSock.Listen (5);
// Set asynchronous method Accept client connection _svrsock.beginAccept (new asyncCallback (acconn), _svrsock;
_ismun = true;
} /// /// Stop server program, all connections to the client will close /// summary> public virtual void stop () {if (! _ _RUN) {throw ("TCPSVR has stopped "));} // This condition statement must be called before all clients, otherwise error occurs in EndConn_sRun = False;
// Turn off the data connection, responsible for the client considered to force the connection if (_svrsock.connected) {_svrsock.shutdown (socketshutdown.both);
CloseallClient ();
// Clean up resources _svrsock.close (); _SESSIONTABLE = NULL;}
/// /// Close all client sessions, disconnect /// summary> public virtual viid closeallclient () {Client (Session Client in _SessionTable.Values) {Client .Close ();
_SESSIONTABLE.CLEAR ();
/// /// Close a session with the client /// summary> /// Required client session object param> public virtual void CloseSession (session closeclient) {debug.assert (closeclient! = Null);
IF (CloseClient! = null) {closeclient.datagram = null;
_SESSIONTABLE.Remove (CloseClient.id);
_clientcount--; // Client Force Close Link IF (ClientClose! = null) {ClientClose (this, New NetEventArgs (CloseClient);}
CloseClient.close ();}}
/// /// Send data /// summary> /// Client session of the data param> /// Data Packet Param> Public Virtual Void Send (SESSION RECVDATACLIENT, STRING DATAGRAM) {// Get Data Coding Byte [] Data = _Coder.GetencodingBytes (DataGram);
Recvdataclient.ClientSocket.Beginsend (Data, 0, Data.Length, Socketflags.none, New AsyncCallback (SendDataEnd), Recvdataclient.ClientSocket;
}
#ndregion
#Region Protection Method /// /// Turmary Socket, first need to close session /// summary> /// Target Socket Object param> / // The type of client exits param> protected virtual void closeclient (socket client, session.exittype exittype) {debug.assert (client! = null); / / Find whether the client is Presented, if there is no existence, throw an exception session closeclient = FindSession (client); closeclient.typeofexit = exittype;
IF (CloseClient! = null) {CloseSession (CloseClient);} else {throw ("New ApplicationException (" The Socket Objects that need to be closed do not exist ");}}
/// /// Client connection processing function /// summary> /// Socket object to establish a server connection param> Protected Virtual Void Acceptconn (IasyncResulti ) {// If the server stops the service, it is no longer necessary to receive new client IF (! _Srun) {return;}
/ / Accept a client's connection request socket ildserver = (socket) IAR.AsyncState;
Socket Client = Old Server.ndAccept (IAR);
/ / Check if the maximum allowable client number IF (_clientcount == _maxclient) {// server is full, issue notification if (ServerFull! = Null) {ServerFull (this, New NetEventArgs (New session (client))) }} Else {session newsession = new session (client);
_SessionTable.Add (newssion.id, newsession); // Client reference count 1 _clientcount ;
// Start accepting data from the client Client.BeginReceive (_RecvdataBuffuffer, 0, _RecvdataBuffer.length, SocketFlags.none, New AsyncCallback (receiveData), Client);
// New customer segment connection, send a notification if (ClientConn! = Null) {ClientConn (this, new neteventargs (newsession));}}
// Continue to accept the client _svrsock.beginaccept (new asyncCallback (acconn), _svrsock);
/// /// Find session objects /// param> /// found by Socket object NULL, the description does not exist returns> private session FindSession (Socket Client) {sessionid ID = New sessionID ((int) client.handle; return (session) _SessionTable [ID];}
/// /// Accept data completion processing function, asynchronous features are reflected in this function, /// After receiving the data, automatically resolve to string packet /// summary> // / Target Client Socket param> Protected Virtual Void ReceiveData (IASYNCRESULT IAR) {socket client = (socket) IAR.ASYNCSTATE
Try {// If the asynchronous reception is started twice, the endReceive int RECV = Client.Endreceive (IAR) is executed twice when the client exits.
IF (RECV == 0) {// Normal Close CloseClient (Client, Session.exitType.NormaleXit); Return;}
String receiveddata = _Coder.Getencodingstring (_RecvdataBuffer, RECV);
// Release the event IF (Recvdata! = Null) {session (client); debug.assert (SendDataSession! = NULL);
/ / If you define the tail mark of the message, you need to handle multiple cases of information IF (_Resolver! = Null) {if (sendDatasession.DataGram! = Null && senddatassion.DataGram.length! = 0) {// plus The last message of the last message ReceivedData = SendDataSession.DataGram receivedData;}
String [] Recvdatagrams = _Resolver.Resolve (Ref receiveddata);
Foreach (String NewDataGram in Recvdatagram) {// Deep copy, in order to keep DataGram confrontation acloneable copyspace;
Session ClientSession = (session) CopySession.Clone ();
ClientSession.DataGram = newDatagram; // Release a message message Recvdata (this, new neteventargs (clients);}
// The remaining code snippet uses SendDatasession.DataGram = receiveddata; if (sendDatasession.DataGram.length "{sendDatasession.DataGram = null;}} // without defined packets Use else {iCloneable Copysession = (iCloneable) denddatassion;
Session ClientSession = (session) CopySession.Clone ();
ClientSession.DataGram = ReceiveData;
Recvdata (this, New NetEventArgs (ClientSession));}} // end of if (recvdata! = NULL)
/ / Continue to receive data from the client client (_RecvdataBuffer, 0, _RecvdataBuffer.Length, SocketFlags.None, New AsyncCallback (receiveData), client);
} Catch (socketexception ex) {// client exits if (10054 == ex. errorcode) {// Client Force Close CloseClient (Client, Session.exittype.exceptionExit);}} catch (ObjectdisposedException EX) {// Here The implementation is not elegant // When the closesession () is called, the data is received, but int RECV = Client.EndReceive (IAR) is called in the data reception // process; // Access the CloseSession () has been disposed of objects / / I think this is also a non-harmful. If (ex! = Null) {EX = null; // Donothing;}}}
/// /// Send data completion processing function /// summary> /// Target client socket param> protected virtual void senddatand (IasyncResult IAR) {socket Client = (socket) IAR.ASYNCSTATE;
INT Sent = Client.Endsend (IAR);
#ndregion
}
/// /// Provide a client class with TCP network connection services // // ///////////////////////////>: /// Principle: /// 1 . Use asynchronous socket communication and server in accordance with certain communication format, please note that the server's pass ///xfa format must be consistent, otherwise the server program can crash, the whole problem is not overcome, how to judge from byte [] // Its encoding format /// 2. Supports identification of data packet format with tag to complete the transfer of big data packets and adapt to bad networks /////////// Note: / // summary> public class tcpcli {#Region field
/// /// Client and server session /////////////////////// /// Client Has been connected to Server /// summary > Private bool _isconnected = false;
/// /// Receive data buffer size 64K /// summary> public const Int defaultBuffersize = 64 * 1024;
/// /// packet parser /// summary> private damramresolver_resolver;
/// /// Communication format codec /// summary> private coder _coder;
/// /// Receive data buffer /// summary> private bote [] _recvdatabase = new byte [defaultbuffersize];
#ndregion
#REGON event definition
// Need to subscribe to the event to receive the notification of the event, if the subscriber exits, you must cancel the subscription /// /// has been connected to server event /// summary> public event NetEvent ConnectedServer;
/// /// receives data packets /// summary> public evenet NetEvent receiveddatagram;
/// /// Connection Disconnect Event /// summary> Public Event NetEvent DisconnectedServer; #ENDREGON
#region attribute
/// /// Returns the session object between the client and the server //// summary> public session clientsession {get {return_Session;}}
/// /// Returns the connection status between the client and the server /// summary> public bool isconnected {get {returnnected;}}
/// /// Data Packet Analyzer /// summary> Public DataGramresolver resovlver {get {return_resolver;} set {_resolver = value;}}
/// /// encoding decoder /// summary> public coder servercoder {get {return_coder;}}
#endregion #Region public method
/// /// Default constructor, using the default encoding format /// summary> public tcli () {_coder = new coder (CODER.EncodingmothOrd.default);}
/// /// Constructor, use a specific encoder to initialize /// summary> /// Packet Encoder param> public TCPCLI (CODER CODER) {_CODER = CODER;} /// /// connection server /// summary> /// server IP address param> /// server port param> public virtual void connection (isconnected) {i (isconnected) {// Reconnect Debug.Assert (_SESSION! = null);
CLOSE ();
Socket news = new socket (addressfamily.internetwork, sockettype.stream, protocoltype.tcp);
IpendPoint IEP = New IpendPoint (iPaddress.Parse (IP), Port); Newsock.BegInConnect (IEP, New AsyncCallback (Connected), Newsock
}
/// /// Send data message /// summary> /// param> public virtual void send (string data) {if (datagram.length = = 0) {return;}
If (! _isconnected) {throw ("No connection server, no data"));
// Get the coded byte by the message byte [] data = _coder.getencodingBytes (DataGram);
_Session.ClientSocket.begInsend (Data, 0, Data.Length, SocketFlags.none, New AsyncCallback (SenddataEnd), _Session.ClientSocket;
/// /// Close connection /// summary> public virtual void close () {if (! _ isconnected) {return;}
_Session.Close ();
_Session = NULL;
_isconnected = false;
#ndregion
#Region protected method
/// /// data send completion processing function /// summary> /// param> protected version {socket remote = (socket) ) IAR.ASYNCSTATE; INT SENT = Remote.endsend (IAR); debug.assert (Sent! = 0);
/// /// Establish TCP connection post-processing process /// summary> /// Asynchronous Socket param> protected virtual void connection (ivket socket) {socket socket = (Socket) IAR.ASYNCSTATE;
Socket.endConnect (IAR);
// Create a new session _Session = new session (socket); _ISCONNECTED = true;
// Trigger the connection to establish an event if (Connected Server! = Null) {ConnectedServer (this, new neteventargs;});
// Establish a connection to receive data immediately_Session.ClientSocket.BeginReceive (_RecvdataBuffer, 0, DefaultBufferSize, SocketFlags.none, New AsyncCallback (Recvdata), Socket;}
/// /// data reception processing function /// summary> /// asynchronous socket param> protected virtual void recvdata (IasyncResult IAR) {socket remote = IAR.ASYNCSTATE;
Try {int RECV = Remote.EndReceive (IAR);
// Normal exit IF (Recv == 0) {_Session.TypeOfExit = session.exittype.NormaleXit;
IF (disconnectedserver! = null) {disconnectedserver (this, new neteventargs);}
Return;}
String receiveddata = _coder.GetencodingString (_RecvdataBuffer, RECV); // The message IF received by the event release (ReceiveDataGram! = null) {// If the message is analyzed by the packet parser, if the message is defined Mark, you need to handle multiple cases of information IF (_Resolver! = Null) {if (_Session.DataGram! = Null && _ssion.DataGram.length! = 0) {// Plus the last message of the message ReceiveData = _Session.DataGram receiveddata;} String [] recvdatagram = _Resolver.Resolve (Rec ReceiveData);
Foreach (String NewDataGram in Recvdatagram) {// NEED Deep Copy. Because you need to guarantee multiple different packets independently there are iCloneAble CopySession = (iCloneable);
Session ClientSession = (session) CopySession.Clone ();
Clientsession.DataGram = newdatagram;
// Release a message ReceiveDataGram (this, New NetEventArgs (ClientSession);
// The remaining code snippet is used when receiving _Session.Datagram = receiveddata;} // does not define the tail mark of the message, directly give the message subscriber to use else {iCloneable CopySession = (iCloneable) _Session;
Session ClientSession = (session) CopySession.Clone ();
ClientSession.DataGram = ReceiveData;
ReceivedDataGram (this, New NetEventArgs (ClientSession);
}
} // end of if (ReceiveDataGram! = null)
// continue to receive data _session.ClientSocket.BeginReceive (_recvDataBuffer, 0, DefaultBufferSize, SocketFlags.None, new AsyncCallback (RecvData), _session.ClientSocket);} catch (SocketException ex) {// the client exits if (10054 == ex {// server forced shutdown connection, force exit _Session.TypeOfexit = session.exittype.exceptionexit;
IF (disconnectedserver! = null) {disconnectedserver (this, new neteventArgs);}}} else {throw (ex);}} catch (objectdisposedException ex) {// The implementation here is not elegant // When calling CloseSession () At the time of the data reception, int RECV = Client.EndReceive (IAR) will be called in data reception //; // to access the CloseSession () The object I have been disposed // I think this is also hurting. IF (ex! = null) {EX = null; // Donothing;}}} #ENDREGON
}
/// /// Communication coding format provider provides encoding and decoding services for communication services /// You can customize your own encoding method in inherited classes such as data encryption transmission, etc. /// summary> Public class coder {/// /// encoding mode /// summary> private encodingmothord _EncodingMothORD;
PROTECTED CODER ()} public coder (EncodingmothOrd EncodingMothOrd) {_EncodingMothord = EncodingMothOrd;
Public Enum EncodingMothORD {Default = 0, Unicode, UTF8, ASCII,}
/// /// News Data Decoding /// Summary> /// Data required Decoded data param> /// Post-encoded data returns> public virtual string GetEncodingString (byte [] dataBytes, int size) {switch (_encodingMothord) {case EncodingMothord.Default: {return Encoding.Default.GetString (dataBytes, 0, size);} case EncodingMothord.Unicode: {return Encoding .Unicode.GetString (dataBytes, 0, size);} case EncodingMothord.UTF8: {return Encoding.UTF8.GetString (dataBytes, 0, size);} case EncodingMothord.ASCII: {return Encoding.ASCII.GetString (dataBytes, 0 , Size); DEFAULT: {throw (New Exception ");}}
}
/// /// data encoding /// summary> /// Required packet param> /// Post-encoded data returns> public virtual byte [] GetEncodingBytes (string datagram) {switch (_encodingMothord) {case EncodingMothord.Default: {return Encoding.Default.GetBytes (datagram);} case EncodingMothord.Unicode: {return Encoding.Unicode.GetBytes (datagram) ;} case EncodingMothord.UTF8: {return Encoding.UTF8.GetBytes (datagram);} case EncodingMothord.ASCII: {return Encoding.ASCII.GetBytes (datagram);} default: {throw (new Exception ( "undefined code format "));}}}}
/// /// Data Packet Analyzer, by analyzing the received raw data, get the complete data packet. /// Inherit this class can realize its own packet parsing method. /// usually The packet recognition method includes: a method of fixed length, length tag, marker, and the like // / Reality of this class is a method of marking, you can implement other methods //////////// summary> Public Class DataGramResolver {/// /// packet end tag /// summary> private string endtag;
/// /// return end tag /// summary> string endtag {get {return endtag;}}
/// /// Protected default constructor, is provided to inheritance class /// summary> protected DataGramResolver () {
}
/// /// Constructor /// / summary> /// packet end tag param> public datagramRamResolver (String endtag) {if (endtag == NULL ) {Throw ("End Marker cannot be NULL");
IF (endtag == ") {throw (" "end tag symbol can not be empty string"));
THIS.Endtag = endtag;
/// /// parsing message /// summary> /// Raw data, returning unused packet pieces, /// The clip will be saved in Session In the param> /// packet array of DataGram objects, the original data may contain multiple packets returns> public virtual string [] resolve (ref string rawdatagram = new arraylist (); // Tail mark position index int tagIndex = -1;
While (True) {tagIndex = Rawdatagram.indexof (endtag, tagIndex 1); if (tagIndex == -1) {Break;} else {// Follow the end tag to divide the string into two parts String newDatagram = Rawdatagram . Substring (0, tagindex endtag.length);
DataGrams.Add (NewDataGram); if (tagIndex endtag.length> = rawDatagram.length) {rawDatagram = "
Break;
Rawdatagram = rawdatagram.substring (tagIndex endtag.length - newdatagram.length);
// Start from the start position to find tagIndex = 0;}} String [] results = new string [datagrams.count];
DataGrams.copyto (Results);
Return Results;
}
/// /// Client and server session /// // ////////////////> Description: /// Session class contains remote communication The state of the end, these status includes the type of socket, packet content, /// client exits (normal shutdown, forced exiting two types) /// summary> public class session: iCloneable {#Region field
/// /// session ID /// summary> private sessionID;
/// /// Client Send to the server /// Note: In some cases, the message may just be a piece of message instead of //// summary> private string _Datagram; // / /// client socket /// summary> private socket _clisock;
/// /// client's exit type /// summary> private exittype _exittype;
/// /// Exit type enumeration /// summary> public enum exittype {normalexit, ExceptionExit};
# endregion # region properties
/// /// Returns the id /// summary> public sessionid id {get {return_id;}}
/// /// Access session message /// summary> public string database {get {return _datagram;} set {_datagram = value;}} /// /// Socket objects associated with client sessions /// summary> public socket clientsocket {get {return_clisock;
/// /// Access client exit /// summary> public exittype typeofexit {get {return _exittype;}
Set {_exittype = value;}}
#ndregion
#Region method
/// /// uses the Handle value of the socket object as Hashcode, which has a good linear feature. /// summary> /// returns> public override int getHashcode () {Return (int) _clisock.handle;
/// /// Returns whether two sessions represent the same client /// summary> /// param> //// returns > Public override Bool Equals (Object Obj) {session rightobj = (session) Obj; return (int) _clisock.handle == (int) Rightobj.clientSocket.handle;
}
/// /// Overloads toString () method, returns the feature of the session object /// summary> /// returns> public override string toString () {string result = string. Format ("Session: {0}, IP: {1}", _ID, _clisock.remoteEndPoint.toString ());
//Result.c retturn result;}
/// /// Constructor /// summary> /// Socket connection param> public session (Socket Clisock) (CLISOCK) (CLISOCK) (CLISOCK) ! = NULL);
_clisock = clisock;
_id = new sessionId ((int) clisock.handle;}
/// /// Close Session /// summary> public void close () {debug.assert (_clisock! = null); // Turns the acceptance and sending of data _clisock.shutdown (socketshutdown.both) ;
// Clean up resources _clisock.close ();
#ndregion
#Region icloneable member
Object system.icloneable.clone () {session new assion = new session (_clisock); newsession.DataGram = _datagram; newsession.typeofexit = _exittype;
Return new assion;
#ndregion}
/// /// Unique logo A session, auxiliary session object Completes specific features in the Hash table /// summary> public class sessionid {/// // / Socket The object's Handle value must be used to initialize it /// summary> private int _id;
/// /// Return ID value /// summary> public int id {get {return_id;}}
/// /// Constructor /// summary> /// socket Handle Value param> public sessionId (int id) {_id = id;}
/// /// Overload. In order to meet the HashTable key value /// summary> /// param> /// returns> Public override bool equals (object obj) {if (obj! = null) {sessionid right = (sessionid) OBJ;
Return_ID == Right._ID;} else if (this == null) {return true;} else {return false;}}
/// /// overload. In order to comply with HashTable key value /// summary> /// return> public override int getHashcode () {return_id;}
/// /// Overload, in order to facilitate display output /// /// returns> public override string toString () {return_id.tostring ();
}
/// /// server program event parameters contains session objects that excited the event ///////mmary> public class NetEventArgs: Eventargs {#Region field
/// /// Client and server session /// summary> private session _client;
#ndregion
#Region constructor /// /// Constructor /// summary> /// client session param> public neteventargs (session client) {if (null == Client) {throw (new argumentnullexception ());
_client = client;} #ENDREGION
#REGION attribute /// /// Get a session object that excited the event /// summary> public session client {get {return_client;}}
#ndregion}}}