Due to the improper arrangement of the study plan, the perception of WCF has been stagnant. Recently, I used WCF again in my work. I can see the blog post about duplex communication from instructor Jiang and try it out, accumulate. The original thought of WCF duplex communication is that the original client can call the method of the server, and the server can also call the method of the client. After reading the blog post, I found that this duplex is actually implemented through method callback. Next we will first introduce the most basic form of duplex communication, and then introduce a form of duplex communication.
WCF communication performs information interaction and Transmission Based on method calls. When developing the basic mode, you also need to download metadata information to the server to let the client know the method signature defined by the server. This is the contract; in the duplex mode, when the server calls the client method, the caller must also know the method signature. This is also achieved through contract, but the contract definition is not in the client that defines the method, it is still on the server. The server defines the contract and the client downloads the metadata to implement it.
The following defines a contract to allow the client to initiate a connection to the server and wait for the server to callback.
1 [ServiceContract(CallbackContract = typeof(ICallback))]2 interface ILogic3 {4 [OperationContract]5 void ListenToCall();6 }
In the ServiceContract feature, CallbackContract is used, and the callback contract for the table name contract is ICallback. This callback contract is also a custom Interface
1 [ServiceContract]2 interface ICallback3 {4 [OperationContract]5 List<int> GetHourMinuteFromClient();6 }
Like a contract defined by a common model, it is a pure service contract. But when the server wants to call the client's method, it is to call the method in the ICallback interface. Here it is GetHourMinuteFromClient ()
The ILogic interface must be implemented on the server to implement the contract.
1 [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)] 2 public class LogicService:ILogic 3 { 4 5 public void ListenToCall() 6 { 7 ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>(); 8 callback.GetHourMinuteFromClient(); 9 10 }11 }
The implementation method here is the GetHourMinuteFromClient () method of the callback client. It uses OperationContext. Current. GetCallbackChannel to obtain an object that implements ICallback. The specified callback method is called through this object. The other is to assign Reentrant or Multiple to the ConcurrencyMode attribute on the ServiceBehavior feature, so as to avoid the deadlock exception when calling the callback method.
After the metadata information is downloaded from the client, the previous callback contract can be implemented,
1 class ClassCallBack : ILogicCallback 2 { 3 4 public int[] GetHourMinuteFromClient() 5 { 6 7 int[] result= new List<int>() { DateTime.Now.Hour, DateTime.Now.Minute }.ToArray(); 8 9 Console.WriteLine("{0},{1}",result[0],result[1]);10 11 return result;12 }13 }
I do not know whether this is related to the configuration. The interface name obtained from the client is ILogicCallback. It is not the same as that obtained from instructor Jiang's Demo-it is the same as the ICallback interface of the server. Here, the current hour and minute are simply output and returned.
Finally, let's talk about the configuration. Only the binding that supports duplex communication is WSDualHttpBinding and NetTcpBinding (except for custom binding). I used NetTcpBinding here.
1 <system.serviceModel> 2 <services> 3 <service name="Logic.LogicService" behaviorConfiguration="te"> 4
The configuration information of the client is not written by the publisher. It can be used directly from the service reference.
1 <system.serviceModel> 2 <bindings> 3 <netTcpBinding> 4 <binding name="NetTcpBinding_ILogic"> 5 <security mode="None" /> 6 </binding> 7 </netTcpBinding> 8 </bindings> 9 <client>10 <endpoint address="net.tcp://127.0.0.1:8004/LogicService" binding="netTcpBinding"11 bindingConfiguration="NetTcpBinding_ILogic" contract="Proxy.ILogic"12 name="NetTcpBinding_ILogic" />13 </client>14 </system.serviceModel>
Calling the client does not use the channel factory described by instructor Jiang to create client objects, but directly uses a class that implements the ILogic interface. The class is not defined by myself, it is also generated through service reference.
1 static void Main(string[] args) 2 { 3 InstanceContext context = new InstanceContext(new ClassCallBack()); 4 LogicClient client = new LogicClient(context); 5 client.Open(); 6 //using (client as IDisposable) 7 //{ 8 client.ListenToCall(); 9 //Console.ReadKey();10 //}11 Console.ReadKey();12 }
The using statement block is used in instructor Jiang's blog post, but I did not add it here, and did not throw an exception. It will be more secure if I add it!
In practice, the monks have encountered such a situation that network communication has adopted the WCF framework. If you want to change the technology, you have to make a big difference and want to implement communication between the two clients, if you want to use Socket to implement direct communication between two clients, it is relatively simple, but it is troublesome to use WCF, and the client cannot communicate directly between clients, all interactions are sent to the server for calling. Therefore, it can only be implemented using the WCF duplex communication. the WCF server is equivalent to an intermediary in the entire structure.
This is only a communication process. Before the communication, each client must connect to the server, so that the server records the client information. When a client sends a request to communicate with other clients, the server finds the previously recorded information and calls the callback method of the corresponding client. This process has not analyzed the resource usage, but it is feasible after practice.
Based on the above Code, an additional method is required in the contract so that the client can send a fetch request to the server.
1 [ServiceContract(CallbackContract = typeof(ICallback))]2 interface ILogic3 {4 [OperationContract]5 void ListenToCall();6 7 [OperationContract]8 List<int> GetHourMinute ();9 }
The callback contract does not need to be modified, so the class implementing ILogic is changed to this
1 [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)] 2 public class LogicService:ILogic 3 { 4 protected delegate List<int> callbackDelegate(); 5 6 private static Dictionary<string, callbackDelegate> clientLst; 7 8 protected static Dictionary<string, callbackDelegate> ClientLst 9 {10 get11 {12 if (clientLst == null)13 clientLst = new Dictionary<string, callbackDelegate>();14 return clientLst;15 }16 }17 18 public void ListenToCall()19 {20 ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();21 MessageProperties properties = OperationContext.Current.IncomingMessageProperties;22 RemoteEndpointMessageProperty endpoint =23 properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;24 ClientLst[endpoint.Address+endpoint.Port] = callback.GetHourMinuteFromClient;25 26 }27 28 29 public List<int> GetHourMinute ()30 {31 //return new List<int>() { DateTime.Now.Hour, DateTime.Now.Minute };32 List<int> result= ClientLst.First().Value.Invoke();33 34 return result;35 }36 }
The function of ListenToCall is equivalent to reporting the IP address and port number of the client to the server, and recording the delegate of the callback method, this information is stored in a Dictionary set of <string, callbackDelegate>. In the GetHourMinute method of another method, the delegate is called according to the specified IP address and port number, so that the method of the specified client can be called. However, the above Code is just a basic demonstration, many security judgments are not added.
This blog article is over. I would like to ask you for more comments and suggestions on indirect communication between the client. I am willing to accept them. Thank you!