我是否需要在新线程中打开每个客户端消息?

时间:2013-10-02 16:01:20

标签: c# multithreading wcf

我有托管WCF服务的应用程序:

namespace ServiceLibrary
{

        public delegate void StatusEventHandler(Capture capture);

        // You have created a class library to define and implement your WCF service.
        // You will need to add a reference to this library from another project and add 
        // the code to that project to host the service as described below.  Another way
        // to create and host a WCF service is by using the Add New Item, WCF Service 
        // template within an existing project such as a Console Application or a Windows 
        // Application.

        [ServiceContract()]
        public interface IService1
        {
            [OperationContract]
            string ClientMsg(string str);
        }

            [ServiceBehavior(
    ConcurrencyMode = ConcurrencyMode.Multiple,
    InstanceContextMode = InstanceContextMode.PerSession)]
        public class service1 : IService1
        {
            public event StatusEventHandler CapturingEvent;
            public event StatusEventHandler OnProcessExitedEvent;
            public event StatusEventHandler OnFinishEvent;

            public string ClientMsg(string str)
            {
                return DoWork(str);
            }

            private DoWork(string str)
            }
               MyClass obj = New MyClass();
               obj.Start(str); /// Do my job
            }
        }
    }

客户端发送字符串到我的服务器,我打开我的类的实例和这个类打开进程,完成我的工作并返回客户端进程ID号。 这个服务器收到来自多个客户端的消息,所以我想知道每次收到客户端消息时是否需要打开新线程,以避免多个客户端同时向服务器发送消息的情况。

这就是我以主窗体打开服务器连接的方式:

private void connect()
{
    try
    {
        if (!isConnected)
        {
            // Returns a list of ipaddress configuration
            IPHostEntry ips = Dns.GetHostEntry(Dns.GetHostName());

            // Get machine ipaddress
            IPAddress _ipAddress = IPAddress.Parse(tbServerIp.Text);

            // Create the url that is needed to specify where the service should be started
            urlService = "net.tcp://" + _ipAddress.ToString() + ":8000/CapturesService";

            // Instruct the ServiceHost that the type that is used is a ServiceLibrary.service1
            host = new ServiceHost(typeof(ServiceLibrary.service1));
            //ServiceLibrary.service1 serviceInstance = new ServiceLibrary.service1();
            //serviceInstance.CapturingEvent += serviceInstance_StartCapturingEvent;
            //serviceInstance.OnProcessExitedEvent += serviceInstance_OnProcessExitedEvent;
            //host = new ServiceHost(serviceInstance);
            host.Opening += new EventHandler(host_Opening);
            host.Opened += new EventHandler(host_Opened);
            host.Closing += new EventHandler(host_Closing);
            host.Closed += new EventHandler(host_Closed);

            // The binding is where we can choose what transport layer we want to use. HTTP, TCP ect.
            NetTcpBinding tcpBinding = new NetTcpBinding();
            tcpBinding.TransactionFlow = false;
            tcpBinding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
            tcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
            tcpBinding.Security.Mode = SecurityMode.None; // <- Very crucial

            // Add a endpoint
            host.AddServiceEndpoint(typeof(ServiceLibrary.IService1), tcpBinding, urlService);

            // A channel to describe the service. Used with the proxy scvutil.exe tool
            ServiceMetadataBehavior metadataBehavior;
            metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
            if (metadataBehavior == null)
            {
                // Create the proxy object that is generated via the svcutil.exe tool
                metadataBehavior = new ServiceMetadataBehavior();
                metadataBehavior.HttpGetUrl = new Uri("http://" + _ipAddress.ToString() + ":8001/CapturesService");
                metadataBehavior.HttpGetEnabled = true;
                metadataBehavior.ToString();
                host.Description.Behaviors.Add(metadataBehavior);
                urlMeta = metadataBehavior.HttpGetUrl.ToString();
            }

            host.Open();
            isConnected = true;
        }
        else
        {
            if (asyncWorker.IsBusy)
            {
                // Notify the worker thread that a cancel has been requested.
                // The cancel will not actually happen until the thread in the
                // DoWork checks the bwAsync.CancellationPending flag, for this
                // reason we set the label to "Cancelling...", because we haven't
                // actually cancelled yet.
                asyncWorker.CancelAsync();
            }

            host.Close();
            isConnected = false;
        }
    }
    catch (Exception ex)
    {
        isConnected = false;
        MessageBox.Show(ex.Message);
        return;
    }
}

private int StartTsharkProcess(Capture capture)
{
    ProcessExitedEvent += Capture_ProcessExitedEvent;
    string args = string.Format("-i {0} host {1} {2} -a duration:300 -w {3}",
        Interface.interfaceNumber,
        capture.machineIpAddress,
        getTsharkFilter(),
        Path.Combine(LocalPath.localPath, capture.fileName));

    int processId = InvokeProcess(WiresharkProcesses.Tshark, args);
    return processId;
}

1 个答案:

答案 0 :(得分:3)

  

此服务器收到来自多个客户端的消息,所以我想知道每次收到客户端消息时是否需要打开新线程,以避免多个客户端同时向服务器发送消息的情况。

ServiceBehavior属性有ConcurrencyMode Property

  

此属性指示服务实例是否可以处理一个或多个并发执行的线程,如果是单线程,则是否支持重入。

The default service behaviorConcurrencyMode值为ConcurrencyMode.Single。因此,如果需要同时允许多个来电,请使用ConcurrencyMode.Multiple并注明:

  

未进行同步保证。由于其他线程可以随时更改您的服务对象,您必须始终处理同步并声明一致性。

注意:如果服务方法执行长时间运行的任务,则客户端可能会超时。