The socket class of the. NET Framework is actually the managed code version of the socket service provided by winsock32 API. The socket class provides a rich set of methods and attributes for network communication. In most cases, the socket method only sends data to their local Win32 copies and handles any necessary security checks. The socket class allows asynchronous and synchronous data transmission using any protocol listed in protocoltype enumeration. The socket class follows the. NET Framework naming mode of the Asynchronous Method. For example, the synchronous receive method corresponds to the asynchronous beginreceive and endreceive methods.
In fact, a socket can be considered as a data channel between an application (client) and a remote server like a stream. This channel is used to read (receive) data) and write (send ).
One of the innovations provided by the asynchronous mode is that the caller determines whether a specific call should be asynchronous. For the called object, there is no need to execute additional programming to support the asynchronous behavior of its client; In this mode, asynchronous delegation provides this function.
If the application only needs one thread during execution, use the method I introduced in "instance parsing socket programming model". These methods are applicable to the single-thread synchronous operation mode. The synchronous operation mode calls the functions that execute network operations (such as send and receive) until the operation is completed.
To use a separate thread to process communication during execution, use the following methods, which are applicable to asynchronous operation mode. Asynchronous Operation Mode immediately returns the call to the function that executes network operations.
If you are using a connection-oriented protocol (such as TCP), you can use the socket, beginconnect, and endconnect methods to connect to the listener host. You can use the beginsend and endsend methods, or the beginreceive and endreceive methods to perform asynchronous data communication. 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 the datagram, and use beginreceivefrom and endreceivefrom to receive the datagram.
After sending and receiving data, you can use the shutdown method to disable socket. After shutdown is called, you can call the close method to release all resources associated with the socket.
The socket class allows you to use the setsocketoption method to configure the socket. You can use the getsocketoption method to retrieve these settings.
Note that if you write a simple application and only need to synchronize data, you can use tcpclient, tcplistener, and udpclient. These classes provide a simpler and user-friendly interface for socket communication.
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 belong to the application protocol layer and are located in the middle. The socket class is at the transport layer, which is the lowest layer. When the request/response layer and application protocol layer above cannot meet the special needs of applications, you need 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 mode. For example, the synchronous accept method corresponds to the asynchronous beginaccept and endaccept methods.
An Asynchronous Server socket needs a method to start accepting network connection requests, a callback method to process connection requests and start to receive network data, and a callback method to end receiving data. This section will further discuss all these methods.
In the following source code, to start accepting network connection requests, initialize the socket using startlistening, and then start accepting new connections using beginaccept. When a new connection request is received on the socket, the callback method is called. It obtains the socket instance that will process the connection and submits the socket to the thread that will process the request. The callback method is used to implement asynccallback delegation. It returns void and carries a parameter of the iasyncresult type. The following example is the shell program that accepts the callback method: Private void acceptcallback (iasyncresult AR ){}
The beginaccept method has two parameters: asynccallback delegate that accepts the callback method and an object that passes the status information to the callback method. In the following example, the listener socket passes the status parameter to the callback method. In this example, create an asynccallback and start an asynchronous operation to accept an input connection attempt listeningsocket. beginaccept (New asynccallback (acceptcallback), listeningsocket );//
Asynchronous sockets use threads in the system thread pool to process incoming connections. One thread is responsible for accepting connections, the other thread is used to process each incoming connection, and the other thread is responsible for receiving connection data. These threads can be the same thread, depending on the thread allocated by the thread pool. The system. Threading. manualresetevent class suspends the execution of the main thread and sends a signal when the execution can continue.
The accept callback method (acceptcallback in callback) sends a signal to the main application to continue processing, establish a connection with the client, and start to asynchronously read client data. The following example shows the first part of the acceptcallback method. This section of this method sends a signal to the main application thread for it to continue processing and establish a connection with the client.
This section first initializes an instance of the stateobject class and calls the beginreceive method to start asynchronously reading data from the client socket. The final method that needs to be implemented for the asynchronous socket server is the read callback method that returns the data sent by the client. Like the callback method, the read callback method is also an 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 creating a thread, a new instance of the thread class will be created using the threadstart delegate as its unique parameter constructor. However, the thread does not start execution before calling the start method. After start is called, the execution starts from the first line of the method referenced by the threadstart delegate. For example: thread = new thread (New threadstart (threadproc ));
Thread. Start ();
In the following source code, we use manualresetevent to allow threads to communicate with each other by sending signals. Generally, this communication involves the tasks that a thread must complete before other threads perform.
When a thread starts an activity (this activity must be completed before other threads), it calls reset to set manualresetevent to a non-terminating State. This thread can be considered as controlling manualresetevent. The thread that calls waitone on manualresetevent will be blocked and wait for the signal. When the control thread completes the activity, it calls set to send a signal waiting for the thread to continue. And release all the waiting threads.
Once it is terminated, manualresetevent remains terminated until it is manually reset. That is, the call to waitone will be returned immediately.
You can pass a Boolean value to the constructor to control the initial status of manualresetevent. If the initial status is terminated, the value is true; otherwise, the value is false.
// The detailed implementation method of the asynchronous Chat Server is as follows:
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 of 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>
/// Required designer variables.
/// </Summary>
Private system. componentmodel. Container components = NULL;
Public form1 ()
{
//
// Required for Windows Form Designer support
//
Initializecomponent ();
//
// Todo: add Any constructor code after initializecomponent calls
//
}
/// <Summary>
/// Clear all resources in use.
/// </Summary>
Protected override void dispose (bool disposing)
{
If (disposing)
{
If (components! = NULL)
{
Components. Dispose ();
}
}
Base. Dispose (disposing );
}
# Region code generated by Windows Form Designer
/// <Summary>
/// The designer supports the required methods-do not use the code editor to modify
/// Content of this method.
/// </Summary>
Private void initializecomponent ()
{
This. rtbreceive = new system. Windows. Forms. RichTextBox ();
This. rtbsend = new system. Windows. Forms. RichTextBox ();
This.txt Server = new system. Windows. Forms. Textbox ();
This.txt Port = 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.txt server. Location = new system. Drawing. Point (72, 16 );
This.txt server. Name = "txtserver ";
This.txt server. tabindex = 2;
This.txt server. Text = "127.0.0.1 ";
//
// Txtport
//
This.txt port. Location = new system. Drawing. Point (288, 16 );
This.txt port. Name = "txtport ";
This.txt port. size = new system. Drawing. Size (48, 21 );
This.txt port. tabindex = 3;
This.txt port. 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 message ";
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 = "sending 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.txt port );
This.controls.add(this.txt server );
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>
/// Main entry point of 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 ("enter the correct IP address format ");}
Try
{// The connection point to the service is formed through the Host IP address and port number of the combined service, ipendpoint class.
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 the host port
Listeningsocket. Listen (50); // listening port, waiting for 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 the new socket.
// Mysocket = listeningsocket. Accept ();
// A process can create one or more threads to execute some program code associated with the process. Use threadstart to delegate the program code to be 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 [1, 256];
Mysocket. Receive (byterecv, byterecv. length, 0 );
String strrecv = encoding. bigendianunicode. getstring (byterecv );
Rtbreceive. appendtext (strrecv + "\ r \ n ");*/
Done. Reset (); // set the status to non-terminated
Listeningsocket. beginaccept (New asynccallback (acceptcallback), listeningsocket); // starts 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 indicates the state of the asynchronous operation.
{
Done. Set (); // set to terminate
Mysocket = (socket) Ar. asyncstate; // get the status
Handler = mysocket. endaccept (AR); // asynchronously accepts incoming connection attempts and creates a new socket to process remote host communication and obtain results
Try
{
Byte [] bytedata = encoding. bigendianunicode. getbytes ("after preparation, you 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 the status
Int bytessent = handler. endsend (AR); // end the suspended asynchronous sending and return 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); // end the suspended asynchronous read and return the number of bytes received.
Stringbuilder sb = new stringbuilder (); // variable character string for receiving data, which can be modified after being created by appending, removing, replacing, or inserting a character.
SB. append (encoding. bigendianunicode. getstring (buffer, 0, bytesread); // append the 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 + "listener stopped ";
}
Catch {MessageBox. Show ("the listener has not started yet, and disabled 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 ("the connection has not been established and cannot be sent .");}
}
Private void form1_closing (Object sender, system. componentmodel. canceleventargs E)
{
Try
{
Listeningsocket. Close (); // close the scoket connection and release all associated resources before closing the window.
}
Catch {}
}
}
}