zoukankan      html  css  js  c++  java
  • 在线实时聊天的实现

    利用了WCF的Socket实现在线聊天室的服务器端

     
    文/monkeyboyabc  出处/博客园

    1.建立WCF Service,命名为ChatService
    添加引用,

     
    CODE:
    System.ServiceModel.dll
    System.ServiceModel.PollingDuplex.dll
    System.Runtime.Serialization.dll


    2.定义接口IChatService.cs
    CODE:
        [ServiceContract(Namespace = "Silverlight",CallbackContract = typeof(IChatCallback),SessionMode = SessionMode.Required)]
        public interface IChat
        {

            [OperationContract(IsOneWay = true)]
            void Order(Message receivedMessage);

            [OperationContract(IsOneWay = true)]
            void JoinChat(Message receivedMessage);

            [OperationContract(IsOneWay = true)]
            void SayChat(Message receivedMessage);
        }


    相对应的callback接口
     
    CODE:
        [ServiceContract]
        public interface IChatCallback
        {
            [OperationContract(IsOneWay = true)]
            void Receive(Message returnMessage);
        }


    注意:在IChat中的属性 NameSpace一定要是SiliverLight,且在SessionMode中 要标明 SessionMode.Required 否则会出错

    3.在Service文件中 定义服务
    在文件ChatService.cs中添加以下代码:
     
    CODE:
    static Dictionary<string, IChatCallback> chatClients = new Dictionary<string, IChatCallback>();
            static List<string> m_NameList = new List<string>();
            static int guestIndex = 1;

            public void JoinChat(Message receivedMessage)
            {
                IChatCallback chatclient;
                bool userAdded = false;
                string test;
                Message returnMessage;

                string name = receivedMessage.GetBody<string>();

                chatclient = OperationContext.Current.GetCallbackChannel<IChatCallback>();

                test = "Service:JoiningPlease Wait";
                returnMessage = Message.CreateMessage(MessageVersion.Soap11,
                    "Silverlight/IChat/Receive", test);

                chatclient.Receive(returnMessage);

                lock (syncObj)
                {
                    if (name == "Guest")
                    {
                        name = "Guest" + guestIndex.ToString();
                        guestIndex = guestIndex + 1;
                    }
                    if (!chatClients.ContainsKey(name) && name != "" && name != null)
                    {
                        test = "Service:Begin Add User To ChattersList";
                        returnMessage = Message.CreateMessage(MessageVersion.Soap11,
                            "Silverlight/IChat/Receive", test);

                        chatclient.Receive(returnMessage);

                        this.name = name;
                        m_NameList.Add(name);
                        chatClients.Add(name, chatclient);
                        userAdded = true;
                                         
                    }
                    else
                    {
                        test = "Service:User:" + name + "Join fault.Already has this user or User name is NULL";

                        returnMessage = Message.CreateMessage(MessageVersion.Soap11,
                            "Silverlight/IChat/Receive",test );

                        chatclient.Receive(returnMessage);

                        return;
                    }
                }

                if (userAdded)
                {
                    string text2 = "Service:User:" + name + " is already Joined";

                    SendMessageToClient(text2);
                }
            }


    这个方法是对应接口中的JoinChat,将用户添加到会话列表中。
    其中,调用Receive接口将Message返回
    然后,遍利用户字典,将信息发送给所有用户
     
    CODE:
            public void SayChat(Message receivedMessage)
            {
                IChatCallback chatclient = OperationContext.Current.GetCallbackChannel<IChatCallback>();
                string text = receivedMessage.GetBody<string>();

                if(!chatClients.ContainsValue(chatclient))
                {
                    return;
                }

                //TODO: 用更好的方法实现
                for (int i = 0; i < m_NameList.Count; i++)
                {
                    IChatCallback clientInList = chatClients[m_NameList];

                    if (clientInList.Equals(chatclient))
                    {
                        text = m_NameList + " Says: " + text;
                        break;
                    }
                }

                SendMessageToClient(text);
            }

            private void SendMessageToClient(string test)
            {
                //TODO: 用更好的方法实现
                for (int i = 0; i < m_NameList.Count; i++)
                {
                    IChatCallback chatclient = chatClients[m_NameList];

                    Message returnMessage = Message.CreateMessage(MessageVersion.Soap11,
                        "Silverlight/IChat/Receive", test);

                    chatclient.Receive(returnMessage);
                }
            }


    4.添加宿主文件PollingDuplexServiceHostFactory.cs
     
    CODE:
    using System;
    using System.ServiceModel;
    using System.ServiceModel.Activation;
    using System.ServiceModel.Channels;

    namespace SLChat
    {
        public class PollingDuplexServiceHostFactory : ServiceHostFactoryBase
        {
            public override ServiceHostBase CreateServiceHost(string constructorString,
                Uri[] baseAddresses)
            {
                //return new PollingDuplexSimplexServiceHost(baseAddresses);

                PollingDuplexSimplexServiceHost serviceHost = new PollingDuplexSimplexServiceHost(baseAddresses);

                System.ServiceModel.Description.ServiceMetadataBehavior smb = serviceHost.Description.Behaviors.Find<System.ServiceModel.Description.ServiceMetadataBehavior>();
                if (smb != null)
                {
                    smb.HttpGetEnabled = true;
                   
                }
                else
                {
                    smb = new System.ServiceModel.Description.ServiceMetadataBehavior();
                    smb.HttpGetEnabled = true;
                    serviceHost.Description.Behaviors.Add(smb);
                }

                return serviceHost;
            }
        }

        class PollingDuplexSimplexServiceHost : ServiceHost
        {
            public PollingDuplexSimplexServiceHost(params System.Uri[] addresses)
            {
                base.InitializeDescription(typeof(ChatService), new UriSchemeKeyedCollection(addresses));
            }

            protected override void InitializeRuntime()
            {
                // Define the binding and set time-outs.
                PollingDuplexBindingElement pdbe = new PollingDuplexBindingElement()
                {
                    PollTimeout = TimeSpan.FromSeconds(3),
                    InactivityTimeout = TimeSpan.FromMinutes(1)
                };

                // Add an endpoint for the given service contract.
                this.AddServiceEndpoint(
                    typeof(IChat),
                    new CustomBinding(
                        pdbe,
                        new TextMessageEncodingBindingElement(
                        MessageVersion.Soap11,
                        System.Text.Encoding.UTF8),
                        new HttpTransportBindingElement()),
                        "");

                base.InitializeRuntime();
            }
        }
    }


    5.一定不要忘记了 添加一个跨域访问的文件**(折磨我尽一天的问题。。。)
    clientaccesspolicy.xml
     
    CODE:
    <?xml version="1.0" encoding="utf-8"?>
    <access-policy>
      <cross-domain-access>
        <policy>
          <allow-from http-request-headers="*">
            <domain uri="*"/>
          </allow-from>
          <grant-to>
            <resource path="/" include-subpaths="true"/>
          </grant-to>
        </policy>
      </cross-domain-access>
    </access-policy>


    没有这个文件,在Windows自带的IIS中将发布不了,但是在VS2008的IIS是没有问题的

    6.在VS的资源管理器(Solution Explore)右键点击ChatService.svc,点击View MarkUp
    将原来的代码修改为:
     
    CODE:
    <%@ServiceHost language=c# Debug="true" Service="SLChat.ChatService" Factory="SLChat.PollingDuplexServiceHostFactory"%>


    使Service用我自己写的Host发布 而不用配置文件
  • 相关阅读:
    第四章 开始Unity Shader学习之旅(3)
    第四章 开始Unity Shader学习之旅(2)
    第四章 开始Unity Shader学习之旅(1)
    堆中的变量、对象的使用
    goto语句 switch语句
    C/C++走过的坑(基础问题篇)
    EOF 与 getchar()
    char与 int 类型转化问题汇总
    运算符优先级记忆口诀及列表(转)
    SQL基础篇---函数及其函数配套使用的关键字
  • 原文地址:https://www.cnblogs.com/liuguanghuiyes/p/1291110.html
Copyright © 2011-2022 走看看