-1

我有托管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;
}
4

1 回答 1

3

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

ServiceBehavior属性具有ConcurrencyMode 属性

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

默认服务行为具有价值ConcurrencyModeConcurrencyMode.Single因此,如果需要同时允许多个调用,请ConcurrencyMode.Multiple注意使用:

没有同步保证。因为其他线程可以随时更改您的服务对象,所以您必须始终处理同步和状态一致性。

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

于 2013-10-03T07:25:53.600 回答