一、测试时间
客户端: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);
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>
试着改变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了。
奇怪。
先放着吧,学一下其他的。后面再回来。