Source: http://blog.csdn.net/21aspnet/archive/2008/11/20/3341887.aspx
The long connection of Ajax, or the comet that some people refer to, means to connect the server in a XMLHttpRequest way, and the server is not immediately written to the corresponding and returned after the connection. The server remains connected and waits for an event that needs to be notified to the client, which writes the data to the response immediately after the event occurs, when the client receives the event notification in a fairly "real-time" manner. Specific communication model, please refer to this article: "Comet:" Server Push technology based on HTTP long connection, which has been said in detail, I will not repeat.
We then began to discuss how to use. NET to implement this model. The first thing we can think of is that we need a Web service, either a asp.net Web service or a WCF Web service,asp.net AJAX library that supports both. Here, for the sake of simplicity, choose the more familiar asp.net Web service example. Then, we write the following two function signatures:
public void Send (Message message);
Public message wait ();
Where the Send function sends a Message object, and the wait function waits for a messages object. Then, let's discuss some of the details. No events cause timeout
First of all, it is not possible to stay connected for a long time. This is not a problem for servers and clients, but we always have to remember that there may be a wide variety of configuration-weird gateways and proxies that may have a wide variety of time-out rules, so comet is best designed to be a recurring connection. In general, if no event occurs in 30 seconds, the server should notify the client that there is no event, end this request, and then restart the new request to continue waiting.
Can the above function signature be used to return a message with no events? This is obviously possible, we can choose to return NULL to indicate no event, or return a Emptymessage constant, depending on whether we define the message using class or struct. (Even, we can do this by making a message derived class called Nomessagemessage.) ) defines the destination to send
The above function signature can indeed be used to send and receive messages, but no one is named. Someone might say, "send it to someone who can define it by a property in the message class." But the wait () method does not say who the receiver is, and the server side still doesn't know which messages should be sent to you.
Therefore, we introduce the concept of channel, channel use its name to identify, the same name will necessarily be the same channel. When sending and receiving, specify which channel to send by name, so the problem is solved. At this point, the function signature is modified as follows:
public void Send (string channelname, message message);
Public message Wait (string channelname); Reliable Message Queuing
Imagine a possible situation where the server sends you a message that you did not receive successfully, but the server thought it was sent, the message was removed from the queue, and the message was lost forever. Some people may emphasize how reliable TCP, server-side messages sent at the level of TCP if there is a problem, will certainly trigger the socket level of exception, this exception bubble up, the server can intercept, so that send failure, and then do not delete the team first message. But do not forget, the middle is likely to exist agent, if the agent successfully retracted the message, but the agent sent to the client this step failed, the server side will not necessarily occur abnormal.
Therefore, we need to develop a strategy to ensure that downlink messages are always sent to the client. Here, we chose to introduce an ACK-by-one mechanism to confirm the receipt of the message. That is, the server-side message sent to the client comes with an ordinal number, which is sent back to the server side after the client receives the message, and has been confirmed to have received the message. At this point, the function signature changes as follows:
public int Send (string channelname, message message);
Public message Wait (string channelname, int sequence);
In the message we receive with wait (), we should have a sequence attribute that marks its ordinal number. Then, when we execute the next wait (), we pass the value of the number plus 1 through the sequence parameter, letting the server know that we expect the next message to be numbered this way. For example, when we receive a message with the sequence property of 836, the next call to wait () is passed to server 837. Server side should now keep the message number 836 on the first, if the client continues to request message No. 836, prove that it last confiscated, this time still send No. 836 messages to it; If the client requests No. 837 message to prove that it successfully received the NO. 836 message, This time send a message number No. 837 to it.
If not, then what to do. That means that this is a wrong request, maybe even an attack request, because it should not normally happen, and the server can consider throwing an insignificant exception (don't tell the attacker you know he's attacking), or even give a direct Response code for request).
Similar to the wait (), send () can also be added to the ACK mechanism by simply changing the return type from void to int, which is specifically used to pass the message number, implemented in the same way as wait (), but send () is the queue where the client holds the message to be sent. Summary
End Our web service is ready. It's all written up. Only the signature has no function body. Yes, the complex work is left to model to do, the WEB service here is just the equivalent of a view, used to expose the model interface.
In the next article, we'll begin to discuss how to implement a server-side message-passing mechanism.
In the last article, we talked about how to design a asp.net Web service to handle long connection requests. A lot of people are asking questions about this, how to hold a request to keep it open for 30 seconds. This is actually very simple, only need to sleep () on it:
Thread.Sleep (* 1000);
The problem, however, is that we don't have to wait 30 seconds to see if there is an event that needs to be returned, but that there is an event that can be returned at any time within 30 seconds. Therefore, we need a mechanism to check whether an event has occurred during the wait process. Monitor Model
In. NET, the most familiar thread synchronization model should be the monitor model. I've never heard of it. Is the lock keyword in C #, which is actually compiled into a pair of monitor.enter () and Monitor.Exit ().
With the lock command, we can create a critical section for an object, and the code must acquire a lock on the object when it executes to the critical section entrance, and release the lock at the exit of the critical section. However, this model is not very suitable for solving our problems, because we need to wait for an event, if the use of lock to wait, that is, the first outside the Web service to lock the object, and then the event triggered the unlock, then the Web service to enter the critical area smoothly.
In fact, there is a better alternative to this type of blockage, which is the mutex. Mutex Model
Mutex, which is the abbreviation for mutual exclusive, is the meaning of "mutual exclusion". How the mutex works. It's kind of like a bank queuing system, where all the people waiting for service sit in the lobby waiting to be called, and when a service window is idle it sends a signal (signal) to notify the next person waiting for service. In short, all the threads that execute the wait instruction are waiting, and each signal can let a thread end and wait for execution to continue.
In. NET, the actions of wait and signal correspond to the two methods of Mutex.waitone () and Mutex.releasemutex () respectively. We can have the Web service thread use Mutex.waitone () to enter the waiting state and use Mutex.releasemutex () to notify the Web service thread when the event occurs. Since the Mutex.waitone () must be carried out after the Mutex.releasemutex (), the ability to carry it out proves that an event has occurred and that the Mutex.releasemutext () has been invoked, At this point you can safely read the event message. Simple Example
After choosing to use the mutex model, let's write a simple example. First, we'll define a mutex within the webservice derived class, and a string representing the message.
Mutex mutex = new Mutex ();
String message;
Then, we define two WebMethod. In order to simplify the problem, we choose the previous article in the beginning of the two function of the signature, also said that only within a Web service to send their own collection, did not send the concept of the target, there is no concept of timing, there is no reliability design. At the same time, we replace the message type with a normal string so that we can test it.
We first write the function that sends the message:
public void Send (String message) {
this.message = message;
This.mutex.ReleaseMutex ();
}
In this send function, we first put the message into a global variable within the class, and then let the global mutex class release a signal. At this point, if the thread is waiting, it can be executed immediately. If no thread is waiting at this point, the next wait thread executes to the blocked place to continue without blocking.
Now let's write the function to receive the message:
public string Wait () {
This.mutex.WaitOne ();
return this.message;
}
The receive function enters the wait state from the start. After getting the signal, what needs to be done is to return the global message to the client. Hands-on Experience
Finally, we can test our code by asp.net the Web test interface that the Web service itself supports. We open a two browser window, one into send () call, one into the wait () call. We then test it by executing the Send ("Hello") and then executing wait (). At this point you can see "Hello" immediately. Execute send ("Hello") at first by executing wait (), which waits for it to return. You can then see the "Hello" in the "Wait" section. Executed in the following order: Send ("Hello"); Wait (); Send ("World"); Wait (); Executed in the following order: Send ("Hello"); Send ("World"); Wait (); Wait (); Executed in the following order: Wait (); Wait (); Send ("Hello"); Send ("World"); Executed in the following order: Wait (); Send ("Hello"); Wait (); Send ("World");
You will find some strange results: the 3rd Test Returns "World" and "world". The 5th test, which first returns "Hello", is not necessarily the wait () thread that first executes. The latter is not a problem in some cases, especially after a long connection is generally followed by a wait () thread waiting, so we can ignore it. The former, because there is no Message Queuing, we only have a 1-length message window, so we can only cache the last message. We will solve this problem in the next article. Summary
In this article, we see differences in the different threading synchronization models. The lock of the monitor model is essentially a semaphore, a mutex that cannot be continuously signal, and a signal must be sent after a wait to receive the next signal. At the same time, semaphore also limits the signal and wait must be executed on the same line Chengnecheng, while the mutex does not have this restriction. Although. NET is optimized for the monitor model, but it can only be solved through the mutex model in our requirements.
Then, we wrote a small consumer association send and receive functions, to achieve the blocking web Service we want. We also see the problem with no Message Queuing, so be sure to do a message queue next.