Continuation example analysis of asynchronous communication in socket programming model (Part One)

Source: Internet
Author: User
Tags bind constructor continue execution socket thread thread class port number
Programming | The socket class for the asynchronous. NET Framework is actually the managed code version of the socket service provided by the Winsock32 API. Where the socket class provides a rich set of methods and properties for network traffic, in most cases the socket class method simply marshals the data to their native Win32 copy and handles any necessary security checks. The Socket class allows asynchronous and synchronous data transfers to be performed using any of the protocols listed in the ProtocolType enumeration. The Socket class follows the. NET Framework naming pattern of the asynchronous method; For example, the synchronous Receive method corresponds to the asynchronous BeginReceive and EndReceive methods.

In fact, the socket can be treated like a stream stream as a data channel between the application side (client) and the remote server, through which the data is read (received) and written (sent).

One of the innovations offered by the asynchronous pattern is that the caller determines whether a particular invocation should be asynchronous. For the object being invoked, it is not necessary to perform additional programming to support the asynchronous behavior of its clients, in which asynchronous delegates provide this functionality.

If your application requires only one thread during execution, use the methods that I described in the example parsing socket programming model, which apply to single-threaded synchronous operation patterns. Synchronous operation mode calls to functions that perform network operations, such as Send and Receive, wait until the operation completes before returning control to the calling program.

To use a separate thread to process traffic during execution, use the following methods, which apply to the asynchronous operation pattern. An asynchronous operation mode returns an immediate call to a function that performs a network operation.

If you are currently using a connection-oriented protocol (such as TCP), you can use the Socket, BeginConnect, and EndConnect methods to connect to the listening host. Asynchronous data communication can be done by using the BeginSend and Endsend methods, or by using the BeginReceive and EndReceive methods. You can use BeginAccept and endaccept to process incoming connection requests.
If you are using a connectionless protocol (such as UDP), you can use Beginsendto and endsendto to send datagrams and use Beginreceivefrom and Endreceivefrom to receive datagrams.
You can use the Shutdown method to disable the Socket after data sending and data reception is complete. After calling Shutdown, you can call the Close method to free all resources associated with the Socket.

The socket class allows you to configure the socket using the SetSocketOption method. You can use the Getsocketoption method to retrieve these settings.

Note You can consider using TcpClient, TcpListener, and udpclient if you are writing simpler applications and you need to synchronize data transfer only. These classes provide simpler, more user-friendly interfaces for Socket communications.


From the TCP/IP model, the Httpwebreqeust class and HttpWebResponse class in the System.Net namespace belong to the request/response layer. TcpClient, TcpListener, and udpclient These classes belong to the Application protocol layer, in the middle. And the socket class is in the transport layer, is the lowest level. When the request/response layer and the application protocol layer above do not meet the special needs of the application, it is necessary to use the transport layer for socket socket programming.



Asynchronous server sockets use the. NET Framework asynchronous programming model to process Network Service requests. The Socket class follows the standard. NET Framework asynchronous naming pattern, for example, the synchronous Accept method corresponds to the asynchronous BeginAccept and Endaccept methods.

Asynchronous server sockets require a method to begin accepting requests for network connections, a callback method that handles connection requests and begins to receive network data, and a callback method that ends receiving data. All of these methods are discussed further in this section.

In the following source code, to begin accepting a network connection request, the method startlistening initialize the Socket and then starts accepting the new connection using the BeginAccept method. The Accept callback method is invoked when a new connection request is received on a socket. It is responsible for obtaining the socket instance that will handle the connection and submitting the socket to the thread that will process the request. Accept the callback method to implement the AsyncCallback delegate; it returns void and takes a IAsyncResult type parameter. The following example is the shell that accepts the callback method: private void Acceptcallback (IAsyncResult ar) {}

The BeginAccept method takes two parameters: a AsyncCallback delegate that accepts a callback method and an object that is used to pass state information to the callback method. In the following example, the listening Socket is passed to the callback method through the state parameter. This example creates a AsyncCallback to begin an asynchronous operation to accept an incoming connection attempt listeningsocket.beginaccept (new AsyncCallback (Acceptcallback). Listeningsocket);//

Asynchronous sockets use threads in the system's thread pool to handle incoming connections. One thread is responsible for accepting the connection, another thread is used to process each incoming connection, and one is responsible for receiving the connection data. These threads can be the same thread, depending on which thread is assigned by the thread pool. The System.Threading.ManualResetEvent class suspends execution of the main thread and emits a signal when execution can continue.

Accepting the callback method (the Acceptcallback in the previous precedent) is responsible for signaling the main application to continue processing, establish a connection to the client, and begin to read the client data asynchronously. The following example is the first part of the Acceptcallback method implementation. This section of the method signals the main application thread to continue processing and establish a connection to the client.

This section of the Acceptcallback method that begins receiving data from a client socket Initializes an instance of the StateObject class first, and then calls the BeginReceive method to begin the asynchronous reading of the data from the client socket. The final method that needs to be implemented for an asynchronous socket server is a read callback method that returns the data sent by the client. As with the accept callback method, the read callback method is also a AsyncCallback delegate. This method reads one or more bytes from the client socket into the data buffer, and then calls the BeginReceive method again until the data sent by the client is complete.

When you create a thread, a new instance of the thread class is created using the constructor that takes the ThreadStart delegate as its unique parameter. However, the thread does not start executing until the Start method is invoked. When start is invoked, execution begins from the first line of the method referenced by the ThreadStart delegate. As shown in the following example: Thread Thread=new thread (new ThreadStart (ThreadProc));

Thread. Start ();



In the following source code we use the ManualResetEvent to allow the thread to communicate with each other by sending signals. Typically, this communication involves a task that a thread must complete before other threads do so.

When a thread starts an activity that must be completed before another thread completes it, it calls reset to set ManualResetEvent to a non terminating state. This thread can be considered a control ManualResetEvent. The thread that calls the WaitOne on the ManualResetEvent will block and wait for the signal. When the control thread completes the activity, it calls Set to emit a signal that the waiting thread can proceed. And frees all waiting threads.

Once it is terminated, the ManualResetEvent will remain signaled until it is manually reset. That is, the call to WaitOne is returned immediately.

You can control the initial state of a ManualResetEvent by passing a Boolean value to the constructor, or false if the initial state is in the signaled state.



The following is an asynchronous chat server-side Detailed implementation method

Using System;
Using System.Drawing;
Using System.Collections;
Using System.ComponentModel;
Using System.Windows.Forms;
Using System.Data;
Using System.Net;
Using System.Net.Sockets;
Using System.Threading;
Using System.Text;
namespace Chat _socket
{
<summary>
Summary description of the Form1.
</summary>
public class Form1:System.Windows.Forms.Form
{
Private System.Windows.Forms.StatusBar statusBar1;
Private System.Windows.Forms.Label Label1;
Private System.Windows.Forms.Label Label2;
Private System.Windows.Forms.Label label3;
Private System.Windows.Forms.Label label4;
Private System.Windows.Forms.RichTextBox rtbreceive;
Private System.Windows.Forms.RichTextBox rtbsend;
Private System.Windows.Forms.TextBox Txtserver;
Private System.Windows.Forms.TextBox Txtport;
Private System.Windows.Forms.Button Btnlisten;
Private System.Windows.Forms.Button btnsend;
Private System.Windows.Forms.Button btnstop;
Private IPAddress Hostipaddress=ipaddress.parse ("127.0.0.1");
Private IPEndPoint Server;
Private Socket Listeningsocket;
Private Socket handler;
Private Socket Mysocket;
private static ManualResetEvent done=new ManualResetEvent (false);
Private Const int buffersize=256;
Private byte[] Buffer=new byte[buffersize];
string port;
<summary>
The required designer variable.
</summary>
Private System.ComponentModel.Container components = null;

Public Form1 ()
{
//
Required for Windows Forms Designer support
//
InitializeComponent ();

//
TODO: Add any constructor code after the InitializeComponent call
//
}

<summary>
Clean up all resources that are in use.
</summary>
protected override void Dispose (bool disposing)
{
if (disposing)
{
if (Components!= null)
{
Components. Dispose ();
}
}
Base. Dispose (disposing);
}

Code generated #region the Windows forms Designer
<summary>
Designer supports required methods-do not use the Code editor to modify
The contents of this method.
</summary>
private void InitializeComponent ()
{
this.rtbreceive = new System.Windows.Forms.RichTextBox ();
This.rtbsend = new System.Windows.Forms.RichTextBox ();
This.txtserver = new System.Windows.Forms.TextBox ();
This.txtport = new System.Windows.Forms.TextBox ();
THIS.STATUSBAR1 = new System.Windows.Forms.StatusBar ();
This.btnlisten = new System.Windows.Forms.Button ();
This.btnsend = new System.Windows.Forms.Button ();
This.btnstop = new System.Windows.Forms.Button ();
This.label1 = new System.Windows.Forms.Label ();
This.label2 = new System.Windows.Forms.Label ();
This.label3 = new System.Windows.Forms.Label ();
This.label4 = new System.Windows.Forms.Label ();
This. SuspendLayout ();
//
Rtbreceive
//
This.rtbReceive.Location = new System.Drawing.Point (80, 56);
This.rtbReceive.Name = "Rtbreceive";
This.rtbReceive.Size = new System.Drawing.Size (264, 96);
This.rtbReceive.TabIndex = 0;
This.rtbReceive.Text = "";
//
Rtbsend
//
This.rtbSend.Location = new System.Drawing.Point (80, 152);
This.rtbSend.Name = "Rtbsend";
This.rtbSend.Size = new System.Drawing.Size (264, 96);
This.rtbSend.TabIndex = 1;
This.rtbSend.Text = "";
//
Txtserver
//
This.txtServer.Location = new System.Drawing.Point (72, 16);
This.txtServer.Name = "Txtserver";
This.txtServer.TabIndex = 2;
This.txtServer.Text = "127.0.0.1";
//
Txtport
//
This.txtPort.Location = new System.Drawing.Point (288, 16);
This.txtPort.Name = "Txtport";
This.txtPort.Size = new System.Drawing.Size (48, 21);
This.txtPort.TabIndex = 3;
This.txtPort.Text = "19811";
//
StatusBar1
//
This.statusBar1.Location = new System.Drawing.Point (0, 287);
This.statusBar1.Name = "StatusBar1";
This.statusBar1.ShowPanels = true;
This.statusBar1.Size = new System.Drawing.Size (360, 22);
This.statusBar1.TabIndex = 4;
This.statusBar1.Text = "StatusBar1";
//
Btnlisten
//
This.btnListen.Location = new System.Drawing.Point (32, 256);
This.btnListen.Name = "Btnlisten";
This.btnListen.TabIndex = 5;
This.btnListen.Text = "Start listening";
This.btnListen.Click + = new System.EventHandler (This.btnlisten_click);
//
Btnsend
//
This.btnSend.Location = new System.Drawing.Point (144, 256);
This.btnSend.Name = "Btnsend";
This.btnSend.TabIndex = 6;
This.btnSend.Text = "Send Information";
This.btnSend.Click + = new System.EventHandler (This.btnsend_click);
//
Btnstop
//
This.btnStop.Location = new System.Drawing.Point (256, 256);
This.btnStop.Name = "Btnstop";
This.btnStop.TabIndex = 7;
This.btnStop.Text = "Stop Listening";
This.btnStop.Click + = new System.EventHandler (This.btnstop_click);
//
Label1
//
This.label1.Location = new System.Drawing.Point (16, 16);
This.label1.Name = "Label1";
This.label1.Size = new System.Drawing.Size (56, 23);
This.label1.TabIndex = 8;
This.label1.Text = "server:";
//
Label2
//
This.label2.Location = new System.Drawing.Point (216, 16);
This.label2.Name = "Label2";
This.label2.Size = new System.Drawing.Size (64, 23);
This.label2.TabIndex = 9;
This.label2.Text = "Listening port:";
//
Label3
//
This.label3.Location = new System.Drawing.Point (16, 64);
This.label3.Name = "Label3";
This.label3.Size = new System.Drawing.Size (64, 23);
This.label3.TabIndex = 10;
This.label3.Text = "Receive information:";
//
Label4
//
This.label4.Location = new System.Drawing.Point (16, 152);
This.label4.Name = "Label4";
This.label4.Size = new System.Drawing.Size (64, 23);
This.label4.TabIndex = 11;
This.label4.Text = "Send message:";
//
Form1
//
This. AutoScaleBaseSize = new System.Drawing.Size (6, 14);
This. ClientSize = new System.Drawing.Size (360, 309);
This. Controls.Add (THIS.LABEL4);
This. Controls.Add (THIS.LABEL3);
This. Controls.Add (THIS.LABEL2);
This. Controls.Add (THIS.LABEL1);
This. Controls.Add (This.btnstop);
This. Controls.Add (This.btnsend);
This. Controls.Add (This.btnlisten);
This. Controls.Add (THIS.STATUSBAR1);
This. Controls.Add (This.txtport);
This. Controls.Add (This.txtserver);
This. Controls.Add (This.rtbsend);
This. Controls.Add (this.rtbreceive);
This. Name = "Form1";
This. Text = "Chat program-Server";
This. topmost = true;
This. Closing + = new System.ComponentModel.CancelEventHandler (this. Form1_Closing);
This. ResumeLayout (FALSE);

}
#endregion

<summary>
The main entry point for the application.
</summary>
[STAThread]
static void Main ()
{
Application.Run (New Form1 ());
}

private void Btnlisten_click (object sender, System.EventArgs e)
{
Try
{
Hostipaddress=ipaddress.parse (Txtserver.text);
Port=txtport.text;
}
Catch{messagebox.show ("Please enter the correct IP address format");}
Try
{//By combining the host IP address and port number of the service, the IPEndPoint class forms to the service's connection point.
Server=new IPEndPoint (Hostipaddress,int32.parse (port));
Create a socket object to establish a connection with the server
Listeningsocket=new Socket (ADDRESSFAMILY.INTERNETWORK,SOCKETTYPE.STREAM,PROTOCOLTYPE.TCP);
Listeningsocket.bind (Server); Bind this host port
Listeningsocket.listen (50); Listen on the port and wait for the client connection request. 50 is the maximum number of incoming connections that can be accommodated in the queue
statusbar1.text= "Host" +txtserver.text+ "Port" +txtport.text+ "Start listening ..."
Accept extracts the first pending connection request from the connection request queue of the listening socket synchronously, and then creates and returns a new Socket.
Mysocket=listeningsocket.accept ();
A process can create one or more threads to execute part of the program code associated with the process. Use the ThreadStart delegate to specify the program code that is executed by the thread.
Thread Thread=new Thread (new ThreadStart (ThreadProc));
Thread. Start ();
}
catch (Exception ee) {statusbar1.text=ee. Message;}
}
private void ThreadProc ()
{
if (mysocket.connected)
//{
statusbar1.text= "Establish a connection with the customer."
while (true)
{
/*byte[] Byterecv=new byte[256];
Mysocket.receive (byterecv,byterecv.length,0);
String strrecv=encoding.bigendianunicode.getstring (BYTERECV);
Rtbreceive.appendtext (strrecv+ "\ r \ n");
Done.reset (); Set state to non-terminated
Listeningsocket.beginaccept (New AsyncCallback (Acceptcallback), listeningsocket)//Start an asynchronous operation to accept an incoming connection attempt
Done.waitone (); Blocks the current thread until the current thread receives a signal.
}
//}
}
private void Acceptcallback (IAsyncResult ar)//ar represents the state of an asynchronous operation.
{
Done.set ()//set to terminate
mysocket= (Socket) ar. asyncstate; Get status
Handler=mysocket.endaccept (AR); Asynchronously accepts incoming connection attempts and creates new sockets to handle remote host traffic, obtaining results
Try
{
Byte[] Bytedata=encoding.bigendianunicode.getbytes ("Ready, can call" + "\ r \ n");
Call Sendcallback to send data asynchronously,
Handler. BeginSend (Bytedata,0,bytedata.length,0,new AsyncCallback (Sendcallback), handler);
}
catch (Exception ee) {MessageBox.Show (EE). message);}
Thread Thread=new Thread (new ThreadStart (Threadrev));
Thread. Start ();
}

private void Sendcallback (IAsyncResult ar)
{
Try
{
handler= (Socket) ar. asyncstate; Get status
int Bytessent=handler. Endsend (AR);//end pending asynchronous Send, returns the number of bytes sent to the Socket
}
catch{}
}
private void Threadrev ()
{
Handler. BeginReceive (Buffer,0,buffersize,0,new AsyncCallback (readcallback), handler);
}

private void Readcallback (IAsyncResult ar)
{
int Bytesread=handler. EndReceive (AR); Ends a pending asynchronous read, returning the number of bytes received.
StringBuilder sb=new StringBuilder (); A variable-character string that receives data that can be modified after it has been created by appending, removing, replacing, or inserting characters.
Sb. Append (Encoding.BigEndianUnicode.GetString (Buffer,0,bytesread));//Append string
String CONTENT=SB. ToString (); Convert to String
Sb. Remove (0,content. Length); Clear SB Content
Rtbreceive.appendtext (content+ "\ r \ n");
Handler. BeginReceive (Buffer,0,buffersize,0,new AsyncCallback (readcallback), handler);
}
private void Btnstop_click (object sender, System.EventArgs e)
{
Try
{
Listeningsocket.close ();
statusbar1.text= "Host" +txtserver.text+ "port" +txtport.text+ "Monitoring Stop";
}
Catch{messagebox.show ("The listener has not started, the shutdown is invalid");}
}

private void Btnsend_click (object sender, System.EventArgs e)
{
Try
{
String strsend = "Server--->" +rtbsend.text+ "\ r \ n";
byte[] Bytesend = Encoding.BigEndianUnicode.GetBytes (strsend);
Handler. BeginSend (Bytesend,0,bytesend.length,0,new AsyncCallback (Sendcallback), handler);
}
Catch{messagebox.show ("Connection not established, cannot be sent.");}
}

private void Form1_Closing (object sender, System.ComponentModel.CancelEventArgs e)
{
Try
{
Listeningsocket.close ()//closes the Scoket connection and releases all associated resources before the window closes.
}
catch{}
}
}
}






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.