• Silverlight异步Socket通信


    真是撞衫了,本来写好个DEMO,打算今天发上来的,可是早上发现翁玉礼http://www.cnblogs.com/wengyuli/同学也发了一个,不过翁同学是用来实现视频聊天的,我是打算用来实现XMPP的;既然大家都对SOCKET这么有兴趣,就放上来一起研究。
    先看下实现效果
    服务端WPF:

    多个用户连接服务端,服务端接收所有用户发过来的信息,也可以向指定的用户发送信息。
    客户端Silverlight:


    客户端向服务端发送信息,并接收服务端发过来的信息。
    这个DEMO的代码参考了这个http://msdn.microsoft.com/zh-cn/magazine/dd315415.aspx,还是官方的代码信得过!Silverlight的客户端没的说,只能用异步Socket实现,WPF的服务端也采用了.net 3.5以后才出现的异步Socket,据说这样可以大大增强服务器端的处理能力。
    项目结构如图:

    分为三个项目:服务端,客户端和用来宿主SL的web项目,服务端打开两个端口,943和4530,943用来向Silverlight提供跨域文件,4530用来和Silverlight程序通信,我主要说说这个DEMO里面我觉得比较好的地方:
    1、客户端和服务端全部采用异步Socket,而没有采用多线程实现,增强程序稳定性,增强程序处理能力,例如信息接收部分:

    代码
      public void ReceiveAsync()
            {
                ReceiveAsync(_receiveSocketArgs);
            }

            
    private void ReceiveAsync(SocketAsyncEventArgs socketAsyncEventArgs)
            {
                
    if (!_acceptedSocket.ReceiveAsync(socketAsyncEventArgs))
                {
                    ReceiveCallback(_acceptedSocket, socketAsyncEventArgs);
                }
            }

            
    void ReceiveCallback(object sender, SocketAsyncEventArgs e)
            {
                
    if (e.SocketError != SocketError.Success)
                {
                    
    return;
                }
                _receiveBuffer.Offset 
    += e.BytesTransferred;
                
    if (_receiveBuffer.IsMessageReceived())
                {
                    
    if (OnReceive != null)
                    {
                        NetworkMessage msg 
    = NetworkMessage.Deserialize(_receiveBuffer.Buffer);
                        _receiveBuffer.AdjustBuffer();
                        OnReceive(
    thisnew ReceiveArgs(msg));
                    }
                }
                
    else
                {
                    
    //adjust the buffer pointer
                    e.SetBuffer(_receiveBuffer.Offset, _receiveBuffer.Remaining);
                }
                
    //queue a an async read request
                ReceiveAsync(_receiveSocketArgs);
            }

    2、这篇文章中http://www.cnblogs.com/yjmyzz/archive/2009/12/02/1615204.html说的粘包的现象,好像在这个DEMO中是没有的,不知道我说的对不对?还望高人指点。
    这里将发送数据进行封包,序列化并转化为byte数组后再发送,接收端执行同样相反的拆包动作,将要发送的数据大小放在封包好的byte数组的前四位,接收端配合接收缓冲,用来判断包是否已经被完整收到。

    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
    using System.IO;

    namespace SilverlightSocketDemo.Server
    {
        [XmlInclude(
    typeof(MyMessage))]
        
    public abstract class NetworkMessage
        {
            
    public static readonly int LENGTH_BYTES = 4;
           
            
    //first 4 bytes of the buffer will contain the length of the serialized NetworkMessage
            
    //this function treats input argument as immutable
            public static NetworkMessage Deserialize(byte[] buffer)
            {
                
    int length = BitConverter.ToInt32(buffer, 0);
                
    int startIndex = sizeof(int);
                
    string strNetworkMessage = Encoding.UTF8.GetString(buffer, startIndex, length);

                StringReader stringReader 
    = new StringReader(strNetworkMessage);
                XmlSerializer xmlSerializer 
    = new XmlSerializer(typeof(NetworkMessage));
                
    return (NetworkMessage)xmlSerializer.Deserialize(stringReader);

            }

            
    //the first 4 bytes of the serialized byte array will contain the length of the buffer that
            
    //contains the previously serialized NetworkMessage;
            public static byte[] Serialize(NetworkMessage msg)
            {
                StringWriter stringWriter 
    = new StringWriter();
                XmlSerializer xmlSerializer 
    = new XmlSerializer(typeof(NetworkMessage));
                xmlSerializer.Serialize(stringWriter, msg);
                
    byte[] messageBytes = Encoding.UTF8.GetBytes(stringWriter.ToString());
                
    byte[] lengthBytes = BitConverter.GetBytes(messageBytes.Length);
                
    byte[] finalBytes = new byte[lengthBytes.Length + messageBytes.Length];
                
    //copy the length of the serialized object
                Array.Copy(lengthBytes, 0, finalBytes, 0, lengthBytes.Length);
                Array.Copy(messageBytes, 
    0, finalBytes, lengthBytes.Length, BitConverter.ToInt32(lengthBytes, 0));
                
    return finalBytes;
            }

        }

        
    public class MyMessage : NetworkMessage
        {
            
    public string User { getset; }
            
    public string Content { getset; }
            
    public override string ToString()
            {
                
    return User+":"+Content;
            }
        }

        
    public class SocketBuffer
        {
            
    public const int BUFFERSIZE = 1024;
            
    protected byte[] _buffer;
            
    protected int _offset = 0;
            
    public SocketBuffer()
            {
                _buffer 
    = new byte[BUFFERSIZE];
            }
            
    public SocketBuffer(int size)
            {
                _buffer 
    = new byte[size];
            }
            
    public byte[] Buffer
            {
                
    get { return _buffer; }
                
    set { _buffer = value; }
            }
            
    //offset will allways indicate the length of the buffer that is filled
            public int Offset
            {
                
    get { return _offset; }
                
    set { _offset = value; }
            }

            
    public int Remaining
            {
                
    get { return _buffer.Length - _offset; }
            }
        }

        
    public class ReceiveBuffer : SocketBuffer
        {
            
    //removes a serlialized message from the buffer, copies the partial message to the begining
            
    //and adjusts the offset
            public void AdjustBuffer()
            {
                
    int messageSize = BitConverter.ToInt32(_buffer, 0);
                
    int lengthToCopy = _offset - NetworkMessage.LENGTH_BYTES - messageSize;
                Array.Copy(_buffer, _offset, _buffer, 
    0, lengthToCopy);
                _offset 
    = lengthToCopy;
            }
            
    //this method checks if a complete message is received
            public bool IsMessageReceived()
            {
                
    if (_offset < 4)
                    
    return false;
                
    int sizeToRecieve = BitConverter.ToInt32(_buffer, 0);
                
    //check if we have a complete NetworkMessage
                if ((_offset - 4< sizeToRecieve)
                    
    return false//we have not received the complete message yet
                
    //we received the complete message and may be more
                return true;
            }
        }
    }
  • 相关阅读:
    eclipse快捷键
    Struts2框架(8)---Struts2的输入校验
    Struts2框架(5)---result结果集
    Spring框架(6)---AspectJ实现AOP
    Spring框架(4)---AOP讲解铺垫
    Spring框架(3)---IOC装配Bean(注解方式)
    Spring框架(2)---IOC装配Bean(xml配置方式)
    Spring框架(1)---Spring入门
    Mybatis框架(5)---动态sql
    Mybatis框架(4)---输入输出映射
  • 原文地址:https://www.cnblogs.com/xiaozhuang/p/1778091.html
Copyright © 2020-2023  润新知