WCF开发(2) 时间、字符长度

一、测试时间

客户端:Program

        static void Main(string[] args)
        {
            MyContractClient client = new MyContractClient();
            Console.WriteLine(client.MyMethod());
            Console.WriteLine(client.MyMethod());
            Console.Read();
            client.Close();
        }

服务端:MyContractClient

        public string MyMethod() {
            Console.WriteLine("[{0}] MyMethod Start",DateTime.Now.ToString("hh:mm:ss.ffff"));
            string msg= base.Channel.MyMethod();
            Console.WriteLine("[{0}] MyMethod End", DateTime.Now.ToString("hh:mm:ss.ffff"));
            return msg;
        }

结果:


解析:

客户端第一次调用在8267,返回在8768,用时501ms;第二次调用在8773,立刻就返回了,而后关闭。

服务端第一次响应在8723,距离8267,用时456ms;第二次响应在8773,立刻响应。

可以认为,建立连接用时约450ms。

修改客户端:

        static void Main(string[] args)
        {
            {
                MyContractClient client = new MyContractClient();
                Console.WriteLine(client.MyMethod());
                Console.WriteLine(client.MyMethod());
                client.Close();
            }

            {
                MyContractClient client = new MyContractClient();
                Console.WriteLine(client.MyMethod());
                Console.WriteLine(client.MyMethod());
                Console.Read();
                client.Close();
            }
        }


结果:

客户端:第1次调用用时447ms,第2次用时5ms,断开,第3次用时94ms,第4次用时5ms。

服务端:第1次响应用时392ms,返回到客户端结束用时55ms;第2次响应用时5ms,立刻返回;第3次响应89ms,用时5ms;第4次立刻响应,返回用时5ms。

再次修改客户端

        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("count:"+(i+1));
                MyContractClient client = new MyContractClient();
                Console.WriteLine(client.MyMethod());
                Console.WriteLine(client.MyMethod());
                Console.WriteLine(client.MyMethod());
                client.Close();
            }
            Console.Read();
        }

结果:


第1次用时46ms,以后用时都是10ms一下。怎么比前面的快了一个数量级啊,电脑的状态不同吗?

结论:

第一次建立连接最耗时,不断开的情况下基本不会有延时,端口后重新建立连接有一点延迟,但是是第一次的1/5。

教程中建议每次都重新创建一个代理类的,应该是没问题的,具体情况再具体分析。


======================================================================================================================================================

二、测试接收数据

1.修改服务契约内容(WCFServiceLib里面的)

    [ServiceContract]
    public interface IMyContract
    {
        [OperationContract]
        string MyMethod();

        [OperationContract]
        string GetString(int count,string item);
    }

    public class MyService:IMyContract
    {
        public string MyMethod()
        {
            Console.WriteLine("[{0}] MyMethod Start", DateTime.Now.ToString("hh:mm:ss.ffff"));
            return "Hello1";
        }

        public string GetString(int count, string item)
        {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < count; i++)
            {
                builder.Append(item);
            }
            return builder.ToString();
        }
    }

2.点击WCFClientConsole里面的ServiceReference1的右键中的更新服务菜单,结果Refrence.cs中的文件变为最开始的原始代码,没有我添加的时间大约代码。
但是,没有更新到GetString函数!
删除 ServiceReference1重新添加服务引用也是没有。
检查后发现是我项目的生成位置变了,后来为了启动方面将几个项目的生成目录变为同一个文件夹,修改后契约后启动了原来的服务端exe。
服务更新功能没问题,能更新到GetString函数,就是原来的打印时间代码没有了。
3.测试客户端
        static void Main(string[] args)
        {
            TestCount(1000);
            TestCount(10000);
            TestCount(100000);
            TestCount(1000000);
            TestCount(10000000);
            Console.Read();
        }

        private static void TestCount(int count)
        {
            Console.WriteLine("TestCount:"+count);
            MyContractClient client = new MyContractClient();
            client.GetString((int) count, "ABC");
            client.GetString((int) count, "ABC");
            client.GetString((int) count, "ABC");
            client.Close();
        }
本来想看看传递的字符串长度对时间的影响的,结果在100000时,出错了
本来以为临界值是65536(2^16),用
TestCount(65535);
            TestCount(65536);
            TestCount(65537);
测试,下面也是改成了client.GetString((int) count, "A");,结果65535也不行。
经过试验,65371是可以的最大值,65372就不行了。
 TestCount(10000);
            TestCount(20000);
            TestCount(30000);
            TestCount(40000);
            TestCount(50000);
            TestCount(60000);
            TestCount(65000);
            TestCount(65100);
            TestCount(65200);
            TestCount(65300);
            TestCount(65310);
            TestCount(65320);
            TestCount(65330);
            TestCount(65340);
            TestCount(65350);
            TestCount(65360);
            TestCount(65370);
            TestCount(65371);//65536的临界值
            TestCount(65372);
            TestCount(65373);
            TestCount(65374);
            TestCount(65375);
            TestCount(65376);
            TestCount(65377);
            TestCount(65378);
            TestCount(65379);
            TestCount(65380);
            TestCount(65390);
            TestCount(65400);
            TestCount(65500);
另外将下面的字符串"A"改成"AB"的话最值是32685,65371/2=32685.5。
65536-65371=165,本来以为这165的字符串用于传递具体内容外的数据(WCF本身的协议数据之类的)。
但是,将655371长度的字符写入txt中发现,

大小是65371字节,也就是我写入的字符串的长度,占用空间变成了65536字节,正好是64KB。
还以为有什么联系,突然想到,文件是按KB存的吧,不够1KB也是要占用1KB空间的(测试了一下确实这样)。
那两种没有关系了,那还是回到原来的存格式数据的假设了。

查到一个资料说处理方法修改配置文件
http://mp.blog.csdn.net/postedit/79063549
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
              <binding name="WSHttpBinding_ISyncService" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" >
                <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647"
        maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
              </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8732/SyncService/" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_ISyncService" contract="SyncServiceProxy.ISyncService"
                name="WSHttpBinding_ISyncService">
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>
那就是修改Binding中的MaxReceivedMessageSize的大小为2147483647( 2^31-1),
修改配置文件
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_IMyContract" maxReceivedMessageSize="2147483647"/>
            </netTcpBinding>
        </bindings>

可以了,轻松跨过65536的坎了。
试着改变maxReceivedMessageSize,并看看最大值
	    TestGetString(65368);
            TestGetString(65369);//65534
            TestGetString(65370);//65535
            TestGetString(65371);//65536 --
            TestGetString(65372);//65537
            TestGetString(65373);//65538
            TestGetString(65374);
确实会随着maxReceivedMessageSize改变而改变,并且差值不变。
但是,
修改为70000后,最大值是69833。相差了167,和165不同。
奇怪??
因为时间有限,不做更多的实验了。总之先有个差值,差值不固定。

接下来测试2147483647这个值

            for (int i = 1; i <= 9; i++)
            {
                TestCount(100000 * i);//5个0
            }
            for (int i = 1; i <= 9; i++)
            {
                TestCount(1000000 * i);//6个0
            }
            for (int i = 1; i <= 20; i++)
            {
                TestCount(10000000 * i);//7个0
                //120000000或者130000000内存溢出了
            }
            //TestCount(2147483647);
            //TestCount(2147483648);
            Console.Read();
结果是:


除了第一次,到5000000(6个0)为止在100ms以内,到50000000(7个0)为止在1000ms以内。90000000达到了2000ms,到120000000内存溢出了,最长时间是110000000的2500ms。
保存到文件中

5000000 100ms4.76MB
50000000 1000ms47.6MB
90000000 2000ms85.8MB
100000000: 22 00ms95.3MB
110000000 : 2500ms 104MB
也就是说2.5s能传100MB的数据,50MB左右的数据用时1s,5M左右用时0.1s。


暂时先这样。这个是同一台电脑的情况,以后再测试不同电脑的情况。

--------------------------------------------------------------------------------
刚刚的是在VS中运行的情况,后来发现用exe运行并不会在120000000或者130000000时溢出。
130000000
2147483647
还差了一个数量级


在270000000时内存溢出了,那样的话。
直接跳过用2147483647测试的话,服务端会崩溃,客户端这边则会超时。
时间上没什么差别。

maxBufferPoolSize属性感觉没什么影响,加上和不加。而且反而是不加时更不容易出现内存异常的情况,加上基本是27结束,不加最高的40过。
NetTcpBinding的默认值:
MaxBufferSize:65536
MaxBufferPoolSize:524288
MaxReceivedMessageSize:65536
在配置文件中将MaxReceivedMessageSize修改为2147483647后,MaxBufferSize也变成了2147483647。

======================================================================================================================================================
三、测试发送时间
1.修改契约,添加SendMessage函数
        public int SendString(string msg)
        {
            return msg.Length;
        }
2.客户端测试
        static void Main(string[] args)
        {
            for (int i = 1; i <= 10; i++)
            {
                TestSendString(10000*i);
            }
            Console.Read();
        }

        private static void TestSendString(int count)
        {
            Console.WriteLine("TestSendString:"+count);
            string msg = GetString(count, "A");
            MyContractClient client = new MyContractClient();
            client.SendString(msg);
        }
3.最值
还是有最大字符串长度的限制的

远程通道的话,就是要设置服务端的属性了吧。
 for (int i = 1; i <= 5; i++)
            {
                TestSendString(10000*i);
            }
            TestSendString(60000);
            TestSendString(65000);
            TestSendString(65100);
            TestSendString(65200);
            TestSendString(65210);//最大值
            TestSendString(65211);
经过测试发现65210是默认的可发送的最大值,
65536-65210=326。

设置什么属性呢?

在百度上查"QuotaExceededException: 传入消息已超过远程通道的最大消息大小",容易找到"已超过传入消息(65536)的最大消息大小配额"的相关信息,这个是客户端的接收最大值,也就是前面的问题。
找到一个信息
http://bbs.csdn.net/topics/340067871

    <behaviors>
      <endpointBehaviors>
        <behavior name="ImsiCallBackbehavior" >
          <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
搜索maxItemsInObjectGraph,能找到一些有用的信息,由于我现在服务端没有配置文件,纯代码的,要能做到用代码添加这个配置的属性。
用DataContractSerializerOperationBehavior 按F1,找到官方:
https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.ServiceModel.Description.DataContractSerializerOperationBehavior);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)&rd=true

private void DataContractBehavior()
{
    WSHttpBinding b = new WSHttpBinding(SecurityMode.Message);
    Uri baseAddress = new Uri("http://localhost:1066/calculator");
    ServiceHost sh = new ServiceHost(typeof(Calculator), baseAddress);
    sh.AddServiceEndpoint(typeof(ICalculator), b, "");

    // Find the ContractDescription of the operation to find.
    ContractDescription cd = sh.Description.Endpoints[0].Contract;
    OperationDescription myOperationDescription = cd.Operations.Find("Add");

    // Find the serializer behavior.
    DataContractSerializerOperationBehavior serializerBehavior =
        myOperationDescription.Behaviors.
           Find<DataContractSerializerOperationBehavior>();

    // If the serializer is not found, create one and add it.
    if (serializerBehavior == null)
    {
        serializerBehavior = new DataContractSerializerOperationBehavior(myOperationDescription);
        myOperationDescription.Behaviors.Add(serializerBehavior);
    }

    // Change the settings of the behavior.
    serializerBehavior.MaxItemsInObjectGraph = 10000;
    serializerBehavior.IgnoreExtensionDataObject = true;

    sh.Open();
    Console.WriteLine("Listening");
    Console.ReadLine();
}
也就是说要加到宿主的终结点的属性中,但是我的代码并没有添加终结点。
修改了一下它的代码,WSHttpBinding改成TcpNetBinding,客户端直接连不了!!
基础不行啊!!
然后发现在默认的ServerHost.Description.Behavorers中(原本就有5个的)有一个ServerBehaverAttribute,里面也有MaxItemsInObjectGraph属性,值已经是最大的2147483647了。而且上面的代码运行下来,serializerBehavior.MaxItemsInObjectGraph值原本也已经是 2147483647了。
奇怪。
先放着吧,学一下其他的。后面再回来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值