我是WCF和WPF的新手。我正在使用WCF和WPF开发客户端服务器聊天应用程序。我用过Nettcpbinding。客户端连接到聊天服务并在服务器上创建会话。然后,他们可以开始与所有连接的用户聊天。一段时间后,当几个人聊天时,一些客户会收到两次或三次聊天消息。 我搜索了类似的案例,但没有发现任何问题。 有谁知道会导致这个问题的原因是什么?
这是服务器上的app.config:
<?xml version="1.0" encoding="utf-8"?><configuration>
<system.serviceModel>
<services>
<service name="WCFService.Service" behaviorConfiguration="behaviorConfig">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:7997/LetsTalkHost/"/>
<add baseAddress="http://localhost:7998/LetsTalkHost/"/>
</baseAddresses>
</host>
<endpoint bindingConfiguration="tcpBinding" address="tcp" binding="netTcpBinding" contract="ServiceAssembly.IChat"/>
<endpoint address="net.tcp://localhost:7996/LetsTalkHost/mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="behaviorConfig">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceThrottling maxConcurrentCalls="1000" maxConcurrentSessions="1000" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="tcpBinding" maxBufferSize="1073741824" maxReceivedMessageSize="1073741824" maxBufferPoolSize="1073741824" transferMode="Buffered" closeTimeout="00:05:00" openTimeout="00:05:00" sendTimeout="00:05:00" maxConnections="1000" portSharingEnabled="false">
<security mode="None">
</security>
<readerQuotas maxDepth="1073741824" maxNameTableCharCount="1073741824" maxArrayLength="1073741824" maxBytesPerRead="1073741824" maxStringContentLength="1073741824"/>
<reliableSession enabled="true"/>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>
这是客户端上的app.config:
<?xml version="1.0" encoding="utf-8"?><configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IChat" closeTimeout="00:02:00" openTimeout="00:02:00"
receiveTimeout="00:10:00" sendTimeout="00:02:00" transactionFlow="false"
transferMode="Buffered" transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard" listenBacklog="10"
maxBufferPoolSize="1073741824" maxBufferSize="1073741824" maxConnections="100"
maxReceivedMessageSize="1073741824">
<readerQuotas maxDepth="1073741824" maxStringContentLength="1073741824" maxArrayLength="1073741824"
maxBytesPerRead="1073741824" maxNameTableCharCount="1073741824" />
<reliableSession enabled="true" />
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IChat"
contract="SVC.IChat" name="NetTcpBinding_IChat" />
</client>
</system.serviceModel>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>
我使用以下项目作为示例:http://www.codeproject.com/Articles/25261/A-WCF-WPF-Chat-Application
主机(服务器)启动服务。该服务的代码如下:
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Controls;
命名空间ServiceAssembly {
[DataContract]
public class Client
{
private string _name;
private string _forname;
private string _surname;
private string _fullname;
private string _nickname;
private string _team;
private string _telephone;
private string _designation;
private DateTime _time;
[DataMember]
public string Name
{
get { return _name; }
set { _name = value; }
}
[DataMember]
public string Forname
{
get { return _forname; }
set { _forname = value; }
}
[DataMember]
public string Surname
{
get { return _surname; }
set { _surname = value; }
}
[DataMember]
public string Fullname
{
get { return _fullname; }
set { _fullname = value; }
}
[DataMember]
public string Nickname
{
get { return _nickname; }
set { _nickname = value; }
}
[DataMember]
public string Team
{
get { return _team; }
set { _team = value; }
}
[DataMember]
public string Telephone
{
get { return _telephone; }
set { _telephone = value; }
}
[DataMember]
public string Designation
{
get { return _designation; }
set { _designation = value; }
}
[DataMember]
public DateTime Time
{
get { return _time; }
set { _time = value; }
}
}
[DataContract]
public class Message
{
private string _sender;
private string _type;
private string _content;
private DateTime _time;
[DataMember]
public string Sender
{
get { return _sender; }
set { _sender = value; }
}
[DataMember]
public string Type
{
get { return _type; }
set { _type = value; }
}
[DataMember]
public string Content
{
get { return _content; }
set { _content = value; }
}
[DataMember]
public DateTime Time
{
get { return _time; }
set { _time = value; }
}
}
[DataContract]
public class FileMessage
{
private string sender;
private string fileName;
private byte[] data;
private DateTime time;
[DataMember]
public string Sender
{
get { return sender; }
set { sender = value; }
}
[DataMember]
public string FileName
{
get { return fileName; }
set { fileName = value; }
}
[DataMember]
public byte[] Data
{
get { return data; }
set { data = value; }
}
[DataMember]
public DateTime Time
{
get { return time; }
set { time = value; }
}
}
[ServiceContract(CallbackContract = typeof(IChatCallback), SessionMode = SessionMode.Required)]
public interface IChat
{
[OperationContract(IsInitiating = true)]
bool Connect(Client client);
[OperationContract(IsOneWay = true)]
void Say(Message msg);
[OperationContract(IsOneWay = true)]
void Whisper(Message msg, Client receiver);
[OperationContract(IsOneWay = false)]
bool SendFile(FileMessage fileMsg, Client receiver);
[OperationContract(IsOneWay = true, IsTerminating = true)]
void Disconnect(Client client);
}
public interface IChatCallback
{
[OperationContract(IsOneWay = true)]
void RefreshClients(List<Client> clients);
[OperationContract(IsOneWay = true)]
void Receive(Message msg);
[OperationContract(IsOneWay = true)]
void ReceiveWhisper(Message msg, Client receiver);
[OperationContract(IsOneWay = true)]
void ReceiverFile(FileMessage fileMsg, Client receiver);
[OperationContract(IsOneWay = true)]
void UserJoin(Client client);
[OperationContract(IsOneWay = true)]
void UserLeave(Client client);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
public class ChatService : IChat
{
Dictionary<Client, IChatCallback> clients = new Dictionary<Client, IChatCallback>();
List<Client> clientList = new List<Client>();
public IChatCallback CurrentCallback
{
get
{
return OperationContext.Current.GetCallbackChannel<IChatCallback>();
}
}
object syncObj = new object();
private bool SearchClientsByName(string name)
{
foreach (Client c in clients.Keys)
{
if (c.Name == name)
{
return true;
}
}
return false;
}
#region IChat Members
public bool Connect(Client client)
{
if (!clients.ContainsValue(CurrentCallback) && !SearchClientsByName(client.Name))
{
lock (syncObj)
{
clients.Add(client, CurrentCallback);
clientList.Add(client);
foreach (Client key in clients.Keys)
{
IChatCallback callback = clients[key];
try
{
callback.RefreshClients(clientList);
callback.UserJoin(client);
}
catch
{
clients.Remove(key);
return false;
}
}
}
return true;
}
return false;
}
public void Say(Message msg)
{
lock (syncObj)
{
foreach (IChatCallback callback in clients.Values)
{
callback.Receive(msg);
}
}
}
public void Whisper(Message msg, Client receiver)
{
foreach (Client rec in clients.Keys)
{
if (rec.Forname == receiver.Forname)
{
IChatCallback callback = clients[rec];
callback.ReceiveWhisper(msg, rec);
foreach (Client sender in clients.Keys)
{
if (sender.Forname == msg.Sender)
{
IChatCallback senderCallback = clients[sender];
senderCallback.ReceiveWhisper(msg, rec);
return;
}
}
}
}
}
public bool SendFile(FileMessage fileMsg, Client receiver)
{
foreach (Client rcvr in clients.Keys)
{
if (rcvr.Name == receiver.Name)
{
Message msg = new Message();
msg.Sender = fileMsg.Sender;
msg.Content = "I'M SENDING FILE.. " + fileMsg.FileName;
IChatCallback rcvrCallback = clients[rcvr];
rcvrCallback.ReceiveWhisper(msg, receiver);
rcvrCallback.ReceiverFile(fileMsg, receiver);
foreach (Client sender in clients.Keys)
{
if (sender.Name == fileMsg.Sender)
{
IChatCallback sndrCallback = clients[sender];
sndrCallback.ReceiveWhisper(msg, receiver);
return true;
}
}
}
}
return false;
}
public void Disconnect(Client client)
{
foreach (Client c in clients.Keys)
{
if (client.Name == c.Name)
{
lock (syncObj)
{
this.clients.Remove(c);
this.clientList.Remove(c);
foreach (IChatCallback callback in clients.Values)
{
callback.RefreshClients(this.clientList);
callback.UserLeave(client);
}
}
return;
}
}
}
#endregion
}
}