-socket Programming _c# Tutorial for common class of TCP connection class

Source: Internet
Author: User
Tags assert constructor int size session id readline
TCP is generally used to maintain a trusted connection, more secure than UDP, in vs.net, there are tcpclient and UdpClient and TcpListener, the general development of the basic can meet the needs, but this has a great disadvantage, For the maintenance of a longer, interactive, data processing is not very clear, Vs/net also has a socket class, with him to do a client/server segment, while the data can be separated from each other, which requires an asynchronous communication process


Implement server segments First:


Using System;


Using System.Net;


Using System.Net.Sockets;


Using System.Text;


Using System.Threading;





State object for reading client data asynchronously


Namespace TCPServer


{


public class StateObject


{


Client socket.


Public Socket worksocket = null;


Size of receive buffer.


public const int buffersize = 1024;


Receive buffer.


Public byte[] buffer = new Byte[buffersize];


Received data string.


Public StringBuilder sb = new StringBuilder ();


}





public class Asynchronoussocketlistener


{


Thread signal.


public static ManualResetEvent alldone = new ManualResetEvent (false);


private static Socket listener;


private int _port=9010;


Public Asynchronoussocketlistener ()


{


}


public void stoplistening ()


{


Listener. Close ();


}


public int Port


{


Set


{


_port=value;


}


}


public void startlistening ()


{


Data buffer for incoming data.


byte[] bytes = new byte[1024];





Establish the local endpoint for the socket.


The DNS name of the computer


Running the listener is "host.contoso.com".


Iphostentry iphostinfo = Dns.resolve (Dns.gethostname ());


IPAddress ipaddress = iphostinfo.addresslist[0];


IPEndPoint localendpoint = new IPEndPoint (ipaddress, _port);





Create a TCP/IP socket.


Listener = new Socket (AddressFamily.InterNetwork,


SocketType.Stream, PROTOCOLTYPE.TCP);





Bind the socket to the "local endpoint" and listen for incoming connections.


Try


{


Listener. Bind (Localendpoint);


Listener. Listen (100);





while (true)


{


Set the event to nonsignaled state.


Alldone.reset ();





Start a asynchronous socket to listen for connections.


Console.WriteLine ("Receive connection ...");


Listener. BeginAccept (


New AsyncCallback (Acceptcallback),


Listener);





Wait until a connection is made before continuing.


Alldone.waitone ();


}





}


catch (Exception e)


{


Console.WriteLine (E.tostring ());


}





Console.WriteLine ("\npress ENTER to continue ...");


Console.read ();





}





private void Acceptcallback (IAsyncResult ar)


{


Signal the main thread to continue.


Alldone.set ();





Get the socket that handles the client request.


Socket listener = (socket) ar. asyncstate;


Socket handler = listener. Endaccept (AR);





Create the state object.


StateObject state = new StateObject ();


State.worksocket = handler;


Handler. BeginReceive (state.buffer, 0, stateobject.buffersize, 0,


New AsyncCallback (Readcallback), state);


}





private void Readcallback (IAsyncResult ar)


{


String content = String.Empty;





Retrieve the state object and the handler socket


From the asynchronous state object.


StateObject state = (stateobject) ar. asyncstate;


Socket handler = State.worksocket;


int bytesread=0;


Read data from the client socket.


if (handler. Connected)


{





Try


{


Bytesread = handler. EndReceive (AR);


}


catch (Exception ex)


{


Handler. Close ();


}








if (Bytesread > 0)


{


There might is more data, and so store the "data received so far."








Check for End-of-file tag. If It is not there, read


More data.


Content = Encoding.ASCII.GetString (


State.buffer,0,bytesread);


if (content). Length>0 && content. EndsWith ("<EOF>"))


{


All of the data has been read from the


Client. Display it on the console.


Console.WriteLine ("Receive {0} bytes data from the client.") \ n Data: {1} ",


Content. Length, content);


Echo the data back to the client.


Send (Handler, "-Data confirmation, has received-<eof>");


}


Else


{


Not all data received. Get more.


Handler. BeginReceive (state.buffer, 0, stateobject.buffersize, 0,


New AsyncCallback (Readcallback), state);


}


}





}





}





private void Send (Socket handler, String data)


{


Convert the string data to byte using ASCII encoding.


byte[] Bytedata = Encoding.UTF8.GetBytes (data);





Begin sending the data to the remote device.


Handler. BeginSend (bytedata, 0, bytedata.length, 0,


New AsyncCallback (Sendcallback), handler);


}





private void Sendcallback (IAsyncResult ar)


{


Try


{


Retrieve the socket from the state object.


Socket handler = (socket) ar. asyncstate;





Complete sending the data to the remote device.


int bytessent = handler. Endsend (AR);


Console.WriteLine ("Send {0} bytes to client.", bytessent);





Handler. Shutdown (Socketshutdown.both);


Handler. Close ();





}


catch (Exception e)


{


Console.WriteLine (E.tostring ());


}


}








}





}





The specific call is as follows:


String p= "";


Asynchronoussocketlistener _server=new Asynchronoussocketlistener ();


_server. Startlistening ();


if (P=console.readline (). ToLower ())!= "Exit")


{


_server. Stoplistening ();


}








Next to the implementation of the client, the client a little more complex, with a session class to maintain a conversation process, coder class to implement a variety of encodings, datagram class to define a specific data packet, default to 64 byte size,





Using System;


Using System.Collections;


Using System.Runtime.InteropServices;


Using System.Diagnostics;


Using System.Net.Sockets;


Using System.Net;


Using System.Text;


Using System.Threading;


Using System.Data;


Using System.Xml;


Using System.Xml.XPath;


Namespace Client


{





#region Communication Object


public delegate void Netevent (object sender, Neteventargs e);


public class CSocket


{


#region Field








<summary>


Session classes between the client and the server


</summary>


Private session _session;





<summary>


Whether the client has connected to the server


</summary>


private bool _isconnected = false;


private bool _isecho = false;


Private StringBuilder sb=new StringBuilder ();


<summary>


Receive Data buffer size 64K


</summary>


public const int defaultbuffersize = 64*1024;





<summary>


Message parser


</summary>


Private Datagramresolver _resolver;





<summary>


Communication Format Codec


</summary>


Private coder _coder;











<summary>


Receive data buffers


</summary>


Private byte[] _recvdatabuffer = new Byte[defaultbuffersize];


public ManualResetEvent alldone = new ManualResetEvent (false);


#endregion





#region Event Definition





You need to subscribe to an event to receive notification of an event, and if the subscriber exits, you must unsubscribe





<summary>


Server event already connected


</summary>








<summary>


Receive Data message events


</summary>


public event Netevent Receiveddatagram;


public event Netevent Disconnectedserver;


public event Netevent Connectedserver;


<summary>


Connection Disconnect Event


</summary>





#endregion





#region Properties





<summary>


Returns the session object between the client and the server


</summary>


Public session Clientsession


{


Get


{


return _session;


}


}





<summary>


Returns the connection status between the client and the server


</summary>


public bool IsConnected


{


Get


{


return _isconnected;


}


}


public bool Isechoback


{


Get


{


return _isecho;


}


}


<summary>


Data Message Analyzer


</summary>


Public Datagramresolver Resovlver


{


Get


{


return _resolver;


}


Set


{


_resolver = value;


}


}





<summary>


Encoder Decoder


</summary>





Public Coder Servercoder


{


Get


{


return _coder;


}


}


#endregion





#region Public method





<summary>


Default constructor, using the default encoding format


</summary>


Public CSocket ()


{


_coder = new Coder (Coder.EncodingMothord.gb2312);


}


<summary>


constructor, using a specific encoder to initialize the


</summary>


<param name= "_coder" > Message encoder </param>


Public CSocket (Coder coder)


{


_coder = coder;


}





<summary>


Connecting to a server


</summary>


<param name= "IP" > server IP Address </param>


<param name= "Port" > Server Ports </param>


public virtual void Connect (string ip, int port)


{


if (isconnected)


{


Close ();


}





Socket newsock= New Socket (AddressFamily.InterNetwork,


SocketType.Stream, PROTOCOLTYPE.TCP);





IPEndPoint IEP = new IPEndPoint (Ipaddress.parse (IP), port);


Newsock. BeginConnect (IEP, new AsyncCallback (Connected), newsock);





}





<summary>


Send data message


</summary>


<param name= "Datagram" ></param>


public virtual void Send (String datagram)


{


Try


{


if (datagram. Length ==0)


{


Return


}








Alldone.waitone ();


Gets the encoded byte of the message


byte [] data = _coder. Getencodingbytes (datagram);


_session. Clientsocket.beginsend (data, 0, data.) Length, Socketflags.none,


New AsyncCallback (Senddataend), _session. Clientsocket);


}





catch (Exception ex)


{


Console.WriteLine (ex. ToString ());


}





}





<summary>


Close connection


</summary>


Public virtual void Close ()


{


if (!_isconnected)


{


Return


}





_session. Close ();





_session = null;





_isconnected = false;


}





#endregion





#region protected methods





<summary>


Data send complete processing function


</summary>


<param name= "IAR" ></param>


protected virtual void Senddataend (IAsyncResult iar)


{





Try


{





Socket remote = (socket) IAR. asyncstate;


int sent = remote. Endsend (IAR);





}


catch (Exception ex)


{


Console.WriteLine (ex. ToString ());


}








}





<summary>


Establish a TCP connection post-processing process


</summary>


<param name= "IAR" > Asynchronous socket</param>


protected virtual void Connected (IAsyncResult iar)


{





Socket socket = (socket) IAR. asyncstate;


Returns a clean connection to the


Socket. EndConnect (IAR);





Create a new session


_session = new session (socket);





_isconnected = true;


Alldone.set ();








Try


{


_session. Clientsocket.beginreceive (_recvdatabuffer, 0,


Defaultbuffersize, Socketflags.none,


New AsyncCallback (RecvData), socket);


catch (Exception ex)


{


Socket. Close ();


}


}





<summary>


Data receive processing function


</summary>


<param name= "IAR" > Asynchronous socket</param>


public string Recevie ()


{


return this.sb.ToString ();


}











protected virtual void RecvData (IAsyncResult iar)


{


Socket remote = (socket) IAR. asyncstate;





Try


{


String Receiveddata= "";


int recv = remote. EndReceive (IAR);


if (recv>0)


{


Receiveddata = System.Text.Encoding.UTF8.GetString (_RECVDATABUFFER,0,RECV);





if (Receiveddata.endswith ("<EOF>"))


{


_isecho=true;


Sb. Append (Receiveddata);


This._session. Datagram= Receiveddata;


if (receiveddatagram==null)


{


Receiveddatagram (this,new Neteventargs (_session));


}





Console.WriteLine (String. Format ("{0}, from {1}", receiveddata,_session.) ClientSocket.RemoteEndPoint.ToString ()));


This.allDone.Set ();


}


Else


{


Console.WriteLine ("Listen");


_session. Clientsocket.beginreceive (_recvdatabuffer, 0, Defaultbuffersize, Socketflags.none,


New AsyncCallback (RecvData), _session. Clientsocket);


}





}














}


catch (SocketException ex)


{


Console.WriteLine (ex. ToString ());


}





}





#endregion








}





<summary>


Communication coding format provider, providing coding and decoding services for communication services


You can customize your own encoding in the inheritance class, such as data encryption transmission, etc.


</summary>


public class Coder


{


<summary>


Encoding method


</summary>


Private Encodingmothord _encodingmothord;





Protected coder ()


{





}





Public coder (Encodingmothord Encodingmothord)


{


_encodingmothord = Encodingmothord;


}





public enum Encodingmothord


{


Gb2312=0,


Default,


Unicode


UTF8,


Ascii


}





<summary>


Communication Data decoding


</summary>


<param name= "Databytes" > Need to decode the data </param>


<returns> encoded Data </returns>


Public virtual string getencodingstring (Byte [] databytes,int size)


{


Switch (_encodingmothord)


{


Case ENCODINGMOTHORD.GB2312:


{


Return encoding.getencoding ("gb2312"). GetString (databytes,0,size);


}


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 ("Undefined encoding format"));


}


}





}





<summary>


Data encoding


</summary>


<param name= "Datagram" > need to encode the message </param>


<returns> encoded Data </returns>


Public virtual byte[] Getencodingbytes (String datagram)


{


Switch (_encodingmothord)


{


Case ENCODINGMOTHORD.GB2312:


{


Return encoding.getencoding ("gb2312"). GetBytes (datagram);


}


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 encoding format"));


}


}


}





}








<summary>


The data Packet Analyzer obtains the complete data message by analyzing the raw data received.


Inheriting this class allows you to implement your own message resolution method.


The usual methods of message recognition include: fixed length, length tag, marker and so on.


The reality of this class is the notation method, you can implement other methods in the inheriting class


</summary>


public class Datagramresolver


{


<summary>


Message end tag


</summary>


private string Endtag;





<summary>


Return end tag


</summary>


String Endtag


{


Get


{


return endtag;


}


}





<summary>


The protected default constructor, which is provided to the inheriting class using the


</summary>


Protected Datagramresolver ()


{





}





<summary>


Constructors


</summary>


<param name= "Endtag" > Message end tag </param>


Public Datagramresolver (String endtag)


{


if (Endtag = null)


{


Throw (new ArgumentNullException ("end tag cannot be null"));


}





if (Endtag = "")


{


Throw (New ArgumentException ("end tag symbol cannot be an empty string"));


}





This.endtag = Endtag;


}





<summary>


Parsing message


</summary>


<param name= "Rawdatagram" > Raw data, returning unused message fragments,


The fragment is saved in the session's datagram object </param>


<returns> message Array, the original data may contain multiple messages </returns>


public virtual string [] Resolve (ref string Rawdatagram)


{


ArrayList datagrams = new ArrayList ();





End Mark Position Index


int Tagindex =-1;





while (true)


{


Tagindex = Rawdatagram.indexof (endtag,tagindex+1);





if (Tagindex = = 1)


{


Break


}


Else


{


Divide the string into about two parts by the end tag


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,


Rawdatagram.length-newdatagram.length);





Start looking from start position


tagindex=0;


}


}





string [] results= new String[datagrams. Count];





Datagrams. CopyTo (results);





return results;


}





}








<summary>


Session classes between the client and the server


///


Version: 1.1


Replacement Version: 1.0


///


Description


The session class contains the state of the remote communication terminal, which includes the socket, the message contents,


Type of client exit (normal shutdown, forced exit two types)


</summary>


public class Session:icloneable


{


#region Field





<summary>


Session ID


</summary>


Private SessionId _id;





<summary>


Messages sent to the server by the client


Note: In some cases the message may be just fragments of the message and incomplete


</summary>


private string _datagram;





<summary>


Socket for Client


</summary>


Private Socket _clisock;





<summary>


Exit type for Client


</summary>


Private Exittype _exittype;





<summary>


Exit Type Enumeration


</summary>


public enum Exittype


{


Normalexit,


Exceptionexit


};





#endregion





#region Properties





<summary>


Returns the ID of the session


</summary>


Public SessionId ID


{


Get


{


return _id;


}


}





<summary>


Access to the message of the session


</summary>


public string Datagram


{


Get


{


return _datagram;


}


Set


{


_datagram = value;


}


}





<summary>


Get the socket object associated with the client session


</summary>


Public Socket Clientsocket


{


Get


{


return _clisock;


}


}





<summary>


Access the client's exit mode


</summary>


Public Exittype Typeofexit


{


Get


{


return _exittype;


}





Set


{


_exittype = value;


}


}





#endregion





#region method





<summary>


Using the handle value of the socket object as the hashcode, it has good linear characteristics.


</summary>


<returns></returns>


public override int GetHashCode ()


{


return (int) _clisock.handle;


}





<summary>


Returns whether two sessions represent the same client


</summary>


<param name= "obj" ></param>


<returns></returns>


public override bool Equals (object obj)


{


Session Rightobj = (session) obj;





return (int) _clisock.handle = = (int) rightObj.ClientSocket.Handle;





}





<summary>


Overload the ToString () method to return the characteristics of the Session object


</summary>


<returns></returns>


public override string ToString ()


{


string result = String. Format ("Session:{0},ip:{1}",


_id,_clisock.remoteendpoint.tostring ());





Result. C


return result;


}





<summary>


Constructors


</summary>


<param name= socket connection used by Clisock > session </param>


Public session (Socket Clisock)


{


Debug.Assert (Clisock!=null);





_clisock = Clisock;





_id = new SessionId ((int) clisock.handle);


}





<summary>


Close session


</summary>


public void Close ()


{


Debug.Assert (_clisock!=null);





Turn off acceptance and delivery of data


_clisock.shutdown (Socketshutdown.both);





Clean up resources


_clisock.close ();


}





#endregion





#region ICloneable Members





Object System.ICloneable.Clone ()


{


Session NewSession = new session (_clisock);


Newsession.datagram = _datagram;


Newsession.typeofexit = _exittype;





return newsession;


}





#endregion


}








<summary>


Unique flag a session in which the secondary session object completes a specific function in the hash table


</summary>


public class SessionId


{


<summary>


The handle value of the socket object for the session object is the same, and you must initialize it with this value


</summary>


private int _id;





<summary>


Return ID value


</summary>


public int ID


{


Get


{


return _id;


}


}





<summary>


Constructors


</summary>


Handle value of <param name= "id" >socket </param>


public SessionId (int id)


{


_id = ID;


}





<summary>


Overload. To conform to the Hashtable key-value feature


</summary>


<param name= "obj" ></param>


<returns></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;


}





}





<summary>


Overload. To conform to the Hashtable key-value feature


</summary>


<returns></returns>


public override int GetHashCode ()


{


return _id;


}





<summary>


Overload, for easy display of output


</summary>


<returns></returns>


public override string ToString ()


{


return _id. ToString ();


}





}








<summary>


The event parameter of the server program that contains the session object that fired the event


</summary>


public class Neteventargs:eventargs


{





#region Field





<summary>


The session between the client and the server


</summary>


Private session _client;





#endregion





#region Constructors


<summary>


Constructors


</summary>


<param name= "Client" > Clients session </param>


Public Neteventargs (Session client)


{


if (null = = client)


{


Throw (new ArgumentNullException ());


}





_client = client;


}


#endregion





#region Properties





<summary>


Get the session object that fired the event


</summary>


Public session Client


{


Get


{


return _client;


}





}





#endregion





}


#endregion


}


The specific call is:





Using System;


Using System.Collections;


Using System.Diagnostics;


Using System.Net.Sockets;


Using System.Net;


Using System.Text;


Using System.Threading;





Namespace test


{


<summary>


Summary description of the CLASS1.


</summary>


Class Class1


{


<summary>


The main entry point for the application.


</summary>


[STAThread]


static void Main (string[] args)


{


//


TODO: Add code here to start the application


//





String op= "";





while ((Op=console.readline ())!= "Exit"


{


if (op!= "")


{


S (OP);


}


}





}





static void S (String d)


{


Client.csocket _socket=new Client.csocket ();


_socket. Connect ("192.168.0.100", 9010);


_socket. Send (d + "<EOF>");


SD ds=new SD ();


_socket. Receiveddatagram+=new client.netevent (DS.ASD);





}


}


Class SD


{





public void ASD (Object Send,client.neteventargs e)


{





}


}


}


With <eof> tag to explain the end of a message, while at various stages can be constructed to make two classes more general, basically completes the socket asynchronous communication, you can add a protocol class, you can use two classes to achieve your business logic agreement, mutual communication


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.