您好!简化代码如下:删了很多,其中登录等待窗口和自定义验证类的代码没加进去。我用的是双工模式DuplexBinding。
客服端
//登录
namespace Client
{
public partial class Login : Form
{
private PleaseWaitDialog pwDlg;
private delegate void HandleDelegate(int popedoms);
private delegate void HandleErrorDelegate();
int flag = 0;
ServiceClient proxy = new ServiceClient(new InstanceContext(new Callback()));
string name = "";
public static int Popedoms;
public Login()
{
InitializeComponent();
}
public int Flag
{
get { return flag; }
set { flag = value; }
}
public string Name
{
get { return name; }
set { name = value;}
}
private void button1_Click(object sender, EventArgs e)
{
string ipaddress = Dns.GetHostAddresses(Dns.GetHostName())[0].ToString();
IAsyncResult iar = MDIMenu.proxy.BeginJoin(textBox_name.Text, textBox_pass.Text, ipaddress, new AsyncCallback(OnEndJoin), null);
pwDlg = new PleaseWaitDialog();
pwDlg.ShowDialog();
}
private void OnEndJoin(IAsyncResult iar)
{
try
{
int popedoms = MDIMenu.proxy.EndJoin(iar);
Popedoms = popedoms;
HandleEndJoin(popedoms);
}
catch
{
HandleEndJoinError();
}
}
private void HandleEndJoinError()
{
if (pwDlg.InvokeRequired)
pwDlg.Invoke(new HandleErrorDelegate(HandleEndJoinError));
else
{
pwDlg.ShowError("错误: 不能连接到服务器!");
ExitChatSession();
}
}
private void HandleEndJoin(int popedoms)
{
if (pwDlg.InvokeRequired)
pwDlg.Invoke(new HandleDelegate(HandleEndJoin), new object[] { popedoms });
else
{
if (popedoms > 0)
{
pwDlg.Close();
Name = textBox_name.Text;
flag = popedoms;
Dispose();
Close();
}
else
{
string str;
switch (popedoms)
{
case 0:
str = "错误:该用户尚未配置权限!";
break;
case -1:
str = "错误:用户名或密码错误!";
break;
case -2:
str = "错误:该用户已经登录!";
break;
default:
str = "错误:登录失败!";
break;
}
pwDlg.ShowError(str);
ExitChatSession();
}
}
}
private void ExitChatSession()
{
try
{
proxy.Leave();
}
catch { }
finally
{
AbortProxyAndUpdateUI();
}
}
private void AbortProxyAndUpdateUI()
{
if (proxy != null)
{
proxy.Abort();
proxy.Close();
proxy = null;
}
// ShowConnectMenuItem(true);
}
private void ExitApplication()
{
Application.Exit();
}
private void Login_Load(object sender, EventArgs e)
{
// button1_Click(sender, e);
}
private void Login_KeyPress(object sender, KeyPressEventArgs e)
{
if ((char)Keys.Enter == e.KeyChar)
button1_Click(sender, e);
}
}
}
//代理类
namespace Client
{
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(Contract.ICallback))]
public interface IService
{
[OperationContract(AsyncPattern = true)]
System.IAsyncResult BeginJoin(string name,string password, string ipaddress, System.AsyncCallback callback, object asyncState);
int EndJoin(System.IAsyncResult result);
[OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = true)]
void Leave();
}
public partial class ServiceClient : DuplexClientBase<IService>, IService
{
public ServiceClient(InstanceContext callbackInstance)
: base(callbackInstance)
{ }
public ServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName)
:
base(callbackInstance, endpointConfigurationName)
{
}
public ServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, string remoteAddress)
:
base(callbackInstance, endpointConfigurationName, remoteAddress)
{
}
public ServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress)
:
base(callbackInstance, endpointConfigurationName, remoteAddress)
{
}
public ServiceClient(System.ServiceModel.InstanceContext callbackInstance, System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress)
:
base(callbackInstance, binding, remoteAddress)
{
}
public System.IAsyncResult BeginJoin(string name, string password, string ipaddress, System.AsyncCallback callback, object asyncState)
{
return base.Channel.BeginJoin(name, password, ipaddress, callback, asyncState);
}
public int EndJoin(System.IAsyncResult result)
{
return base.Channel.EndJoin(result);
}
public void Leave()
{
base.Channel.Leave();
}
}
}
//回调类
namespace Client
{
// 注意: 如果更改此处的类名 "Callback",也必须更新 App.config 中对 "Callback" 的引用。
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Callback : ICallback
{
public delegate void NormalWarningDelegate(byte[] message);
public static event NormalWarningDelegate NormalWarningEvent;
public int ReceiveWhisper(byte[] message)
{
return 1;
}
public void Receive(byte[] message)
{
NormalWarningEvent(message);
}
public void ReturnResult(object[] message)
{
}
}
}
//app.config
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="Client.ClientBehavior">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="Custom" customCertificateValidatorType="Client.CustomX509Validator,Client"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint name="ServiceEndpoint"
address="net.tcp://localhost:8001/Host"
behaviorConfiguration="Client.ClientBehavior"
binding="netTcpBinding"
bindingConfiguration="DuplexBinding"
contract="Client.IService" >
<identity>
<dns value="MyServerCert" />
</identity>
</endpoint>
</client>
<bindings>
<netTcpBinding>
<binding name="DuplexBinding" sendTimeout="00:00:30" maxReceivedMessageSize="655360" >
<readerQuotas maxArrayLength="1638400"/>
<reliableSession enabled="true" />
<security mode="Message">
<message clientCredentialType="UserName"/>
<!--transport clientCredentialType="Windows" /-->
</security>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
接口
namespace Contract
{
// 注意: 如果更改此处的接口名称 "IService",也必须更新 App.config 中对 "IService" 的引用。
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallback))]
public interface IService
{
[OperationContract(IsOneWay = false, IsInitiating = true, IsTerminating = false)]
int Join(string name, string password, string ipaddress );
[OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = true)]
void Leave();
}
}
namespace Contract
{
// 注意: 如果更改此处的接口名称 "ICallback",也必须更新 App.config 中对 "ICallback" 的引用。
[ServiceContract]
public interface ICallback
{
[OperationContract]
int ReceiveWhisper(byte[] message);
[OperationContract(IsOneWay = true)]
void Receive(byte[] message);
[OperationContract]
void ReturnResult(object[] message);
}
}
服务端
//app.config
<system.serviceModel>
<services>
<service name="Host.Service" behaviorConfiguration="Host.ServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8001/Host" />
</baseAddresses>
</host>
<endpoint address="" binding="netTcpBinding" bindingConfiguration="DuplexBinding" contract="Contract.IService" >
<identity>
<dns value="MyServerCert" />
</identity>
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Host.ServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl="" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<serviceCertificate findValue="MyServerCert" storeLocation="LocalMachine"
storeName="My" x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="Host.MyCustonValidator,Host" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="DuplexBinding" sendTimeout="00:00:30" maxReceivedMessageSize="655360" >
<readerQuotas maxArrayLength="1638400"/>
<reliableSession enabled="true" />
<security mode="Message">
<message clientCredentialType="UserName"/>
<!--transport clientCredentialType="Windows" /-->
</security>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
<system.web>
<membership defaultProvider="ClientAuthenticationMembershipProvider">
<providers>
<add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" />
</providers>
</membership>
<roleManager defaultProvider="ClientRoleProvider" enabled="true">
<providers>
<add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400" />
</providers>
</roleManager>
</system.web>
namespace Host
{
// 注意: 如果更改此处的类名 "Service",也必须更新 App.config 中对 "Service" 的引用。
public enum MessageType { Receive, ReturnResult, ReceiveWhisper };
public class ChatEventArgs : EventArgs
{
public MessageType msgType;
public string name;
public int result;
public object[] message;
public byte[] msgbytes;
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service : IService
{
private static Object syncObj = new Object();
ICallback callback = null;
public delegate void ChatEventHandler(object sender, ChatEventArgs e);
public static event ChatEventHandler ChatEvent;
public static Dictionary<string, ChatEventHandler> chatters = new Dictionary<string, ChatEventHandler>();
private string name;
private static string[] list ;
private int popedoms = -2;
private ChatEventHandler myEventHandler = null;
public int Join(string name, string password, string ipaddress)
{
bool userAdded = false;
myEventHandler = new ChatEventHandler(MyEventHandler);
lock (syncObj)
{
if (!chatters.ContainsKey(name) && name != "" && name != null)
{
//popedoms = 读数据库;
if (popedoms > 0)
{
this.name = name;
chatters.Add(name, MyEventHandler);
userAdded = true;
}
}
}
if (userAdded)
{
callback = OperationContext.Current.GetCallbackChannel<ICallback>();
ChatEvent += myEventHandler;
list = new string[chatters.Count];
lock (syncObj)
{
chatters.Keys.CopyTo(list, 0);
}
}
return popedoms;
}
public void Leave()
{
if (name == null)
return;
lock (syncObj)
{
chatters.Remove(this.name);
}
ChatEvent -= myEventHandler;
}
//发送给指定客服端
public void Whisper(string to, byte[] msg)
{
ChatEventArgs e = new ChatEventArgs();
e.msgType = MessageType.ReceiveWhisper;
e.msgbytes = msg;
try
{
ChatEventHandler chatterTo;
lock (syncObj)
{
chatterTo = chatters[to];
}
chatterTo.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
}
catch
{
this.name = to;
Leave();
}
}
public void SendToAllClient(byte[] msg)
{
ChatEventArgs e = new ChatEventArgs();
e.msgType = MessageType.Receive;
e.msgbytes = msg;
BroadcastMessage(e);
}
private void MyEventHandler(object sender, ChatEventArgs e)
{
try
{
switch (e.msgType)
{
case MessageType.Receive:
callback.Receive(e.msgbytes);
break;
case MessageType.ReceiveWhisper:
callback.ReceiveWhisper(e.msgbytes);
break;
case MessageType.ReturnResult:
callback.ReturnResult(e.message);
break;
}
}
catch
{
Leave();
}
}
private void BroadcastMessage(ChatEventArgs e)
{
ChatEventHandler temp = ChatEvent;
if (temp != null)
{
foreach (ChatEventHandler handler in temp.GetInvocationList())
{
handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
}
}
}
private void EndAsync(IAsyncResult ar)
{
ChatEventHandler d = null;
try
{
System.Runtime.Remoting.Messaging.AsyncResult asres = (System.Runtime.Remoting.Messaging.AsyncResult)ar;
d = ((ChatEventHandler)asres.AsyncDelegate);
d.EndInvoke(ar);
}
catch
{
ChatEvent -= d;
}
}
}
}