C#的Socket编程代码片段

来源:互联网 发布:js手机号码中间用星号 编辑:程序博客网 时间:2024/05/02 16:19
Code from shareCache

using COM = MergeSystem.Indexus.WinServiceCommon;
using COMO = MergeSystem.Indexus.WinServiceCommon.Udp.Command;
public bool Send()
        {
            TcpClient client = null;
           
            try
            {
                using (
client = new TcpClient(
                        this.Hostname,
                        Handler.Config.GetIntValueFromConfigByKey(Constants.ConfigServiceCacheIpPort)
                    )
                )
                {
                    // set client parameters
                    client.Client.Ttl = this.Ttl;  //default is 42
                    client.Client.SendTimeout = this.SendTimeout; //default is 1000

                      //发送
                    client.GetStream().Write(this.GetBytes(), 0, this.length);
                    client.GetStream().Flush();

                    // copy all data, so it will be available in the current object!!!
                    this.Copy(new Handler.NetworkMessage().ProcessNetworkMessage(client.Client));
                    client.Client.Blocking = false;  //为什么需要关闭前把关闭设置为非阻塞?
                    client.Close();
                   
                    switch (this.action)
                    {
                        case ActionValue.Successful:
                            {
                                // Action done successfully;
                                return true;
                            }
                        case ActionValue.Error:
                            {
                                // TODO: Error handling somehow, maybe we need to extend
                                // to return an error code or something similar.
                                Console.WriteLine("Error, check the server log!");
                                return false;
                            }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Handler.LogHandler.TrafficException(ex.Message, ex);
                return false;
            }
            finally
            {

                if (client != null)
                {
                    // if(client.Client!=null)
                        //sclient.Client.Blocking = false;
                       
                    if (client.Connected)
                    {
                        client.Close();
                        client.Client.Disconnect(true);
                    }
                }
            }
            return false;
        }
//TCP接收端
public void Init()
        {
            IPHostEntry localMachineInfo = Dns.GetHostEntry(Dns.GetHostName());
            IPEndPoint endpoint = new IPEndPoint(localMachineInfo.AddressList[0], cacheIpPort);

            serverSocket = new Socket(endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            serverSocket.Bind(endpoint);
            serverSocket.Listen((int)SocketOptionName.MaxConnections);

            string msg = string.Format(@"TCP - Listener started on: {0}:{1}", cacheIpAdress, cacheIpPort);
            COM.Handler.LogHandler.Info(msg);
            COM.Handler.LogHandler.Traffic(msg);
            Console.WriteLine(msg);

            // setup listener issues
            acceptThread = new Thread(AcceptConnections);
            acceptThread.IsBackground = true;
            acceptThread.Priority = ThreadPriority.Normal;
            acceptThread.Start();

            if (1 == COM.Handler.Config.GetIntValueFromConfigByKey(COM.Constants.ConfigLoggingEnable))
            {
                COM.Handler.LogHandler.Info("IndeXus.Net Listener Started" + COM.Enums.LogCategory.ServiceStart.ToString());
            }
        }
        private void AcceptConnections()
        {
        

            while (true)
            {
                // Accept a connection
                Socket socket = serverSocket.Accept();
                ConnectionInfo connection = new ConnectionInfo();
                connection.Socket = socket;
                 //启动新线程去处理数据
                // Create the thread for the receive.
                connection.Thread = new Thread(this.ProcessConnection);
                connection.Thread.Name = "TCP Connection Thread";
                connection.Thread.IsBackground = true;
                connection.Thread.Start(connection);

                // Store the socket in the open connections
                lock (this.connections)
                {
                    this.connections.Add(connection);
                }
            }
        }
消息接收
public IndexusMessage ProcessNetworkMessage(Socket socket)
        
{
            
if (socket.Connected)
            
{
                
int readSize = 65000;
                
byte[] buffer = new byte[readSize];
                List
<byte> data = new List<byte>();
                
int bytesRead = 0;
                
int msgLength = readSize;
                
bool readMsgHeader = true;
                
try
                
{
                    Monitor.Enter(bulkObject);
                    socket.Blocking 
= true;
                    
// key part of the server, this loops as long it needs until 
                    
// it receives the whole byte stream of a IndexusMessage
                    do
                    
{
                        
int tmp = msgLength - bytesRead > readSize ? 300 : msgLength - bytesRead;
                        
int read = 0;
                        
try
                        
{
                            read 
= socket.Receive(buffer, 0, tmp, SocketFlags.None);
                        }

                        
catch (SocketException ex)
                        
{            
                        }

                        
if (readMsgHeader)
                        
{
                            msgLength = BitConverter.ToInt32(buffer, 2);
                            readMsgHeader = false
;
                        }

                        
for (int i = 0; i < read; ++i)
                            data.Add(buffer[i]);
                        bytesRead 
+= read;
                    }
 while (bytesRead < msgLength);

                    
lock (bulkObject)
                    
{
                        countTransferData 
+= bytesRead;
                    }

                    
                    
// Console.WriteLine("Total Transfer {0:F2} kb" , countTransferData / (1024*1024) );
                    
                    
if (bytesRead > 0)
                    
{
                        
// create an Object based on network data.
                        MemoryStream stream = new MemoryStream(data.ToArray());
                        stream.Seek(
0, 0);
                        IndexusMessage nMsg 
= new IndexusMessage(stream);
                        
// Testing Purposes.
                        
// Console.WriteLine(nMsg.ToString());
                        return nMsg;
                    }

                    
else
                    
{
                        Console.WriteLine(
"Failed");
                        
return null;
                    }

                }

                
catch (Exception ex)
                
{
                    Handler.LogHandler.TrafficException(ex.Message, ex);
                    
return null;
                }

                
finally
                
{
                    socket.Blocking 
= false;
                    Monitor.Exit(bulkObject);
                }

            }

            
else
            
{
                Console.WriteLine(
"Socket is not connected, therefore its not able to process network message.");
                Handler.LogHandler.Error(
"Socket is not connected, therefore its not able to process network message.");
                
return null;
            }

        }
ProcessConnection中最终关闭socket
finally
            {
                connection.Socket.Disconnect(true);
            }

消息的发送一般需要组织一下。
//格式化的消息,
状态,活动,长度,id, datetime Size+datetime, data size+data
public bool SetBytes(MemoryStream stream)
        {
            BinaryReader br = new BinaryReader(stream);

            this.status = (StatusValue)br.ReadByte();
            this.action = (ActionValue)br.ReadByte();

            this.length = br.ReadInt32();
            this.id = br.ReadInt32();

            // datetime handling
            int expireLength = br.ReadInt32();
            byte[] buf = new byte[expireLength];
            int read = br.Read(buf, 0, expireLength);
            this.expires = Formatters.Serialization.BinaryDeSerialize<DateTime>(buf);
            buf = null;

            // data object handling
            int dataLength = br.ReadInt32();
            buf = new byte[dataLength];
            read = br.Read(buf, 0, dataLength);
            this.data = Formatters.Serialization.BinaryDeSerialize<KeyValuePair<string, object>>(buf);
            buf = null;
            return true;
        }

        /// <summary>
        /// Gets the bytes of an <see cref="IndexusMessage"/> to send over the wire.
        /// </summary>
        /// <returns>A <see cref="T:System.Byte[]"/> Object.</returns>
        public byte[] GetBytes()
        {
            MemoryStream stream = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(stream);

            bw.Write((byte)this.status);
            bw.Write((byte)this.action);
            bw.Write(this.length);
            bw.Write(this.id);

            // datetime
            int size = Formatters.Serialization.BinarySerialize(this.expires).Length;
            byte[] buf = new byte[size];
            buf = Formatters.Serialization.BinarySerialize(this.expires);
            bw.Write(size);
            bw.Write(buf);
            buf = null;

            // object size
            size = Formatters.Serialization.BinarySerialize(this.data).Length;
            buf = new byte[size];
            buf = Formatters.Serialization.BinarySerialize(this.data);
            bw.Write(size);
            bw.Write(buf);
            return stream.ToArray();
        }
       
消息的2进制格式化
public class Translator
    {
        /// <summary>
        /// Toes the binary.
        /// </summary>
        /// <param name="item">The item. A <see cref="T:MergeSystem.Indexus.WinServiceCommon.Udp.Command.AppCommand"/> Object.</param>
        /// <returns>A <see cref="T:System.Byte[]"/> Object.</returns>
        [System.Diagnostics.DebuggerStepThrough]
        public static byte[] ToBinary(AppCommand item)
        {
            BinaryFormatter format = new BinaryFormatter();
            MemoryStream str = new MemoryStream();
            format.Serialize(str, item);
            return str.ToArray();
        }

        /// <summary>
        /// Froms the binary.
        /// </summary>
        /// <param name="data">The data. A <see cref="T:System.Byte[]"/> Object.</param>
        /// <returns>
        /// A <see cref="T:MergeSystem.Indexus.WinServiceCommon.Udp.Command.AppCommand"/> Object.
        /// </returns>
        [System.Diagnostics.DebuggerStepThrough]
        public static AppCommand FromBinary(byte[] data)
        {
            BinaryFormatter format = new BinaryFormatter();
            MemoryStream str = new MemoryStream(data);
            str.Position = 0;
            return (AppCommand)format.Deserialize(str);
        }
    }
   
    //Udp发送方式, 不需要关闭?
    private static void SendCommand(AppCommand cmd, int port, string hostName)
        {
       
           
            byte[] data = Translator.ToBinary(cmd);
            UdpClient sender = new UdpClient();
            IPAddress endAddress = IPAddress.Broadcast;
            sender.EnableBroadcast = true;
            if (hostName != null)
            {
                // IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
                IPHostEntry host = Dns.GetHostEntry(IPAddress.Parse(hostName));
                // IPHostEntry host = Dns.GetHostByName(hostName);
                if (host != null && host.AddressList != null && host.AddressList.Length > 0)
                    endAddress = host.AddressList[0];
               
                sender.EnableBroadcast = false;
            }
            IPEndPoint end = new IPEndPoint(endAddress, port);
            string localhost = Handler.Config.GetStringValueFromConfigByKey(Constants.ConfigServiceCacheIpAddress);
            string infoMsg =
                string.Format(
                    @"SendCommand->command: '{0}' from: '{1}' to: '{2}' ",
                    cmd.CommandType,
                    localhost + (cmd.CommandType == SystemCommandOption.PongClients ? ":" + Ports.PortUdpListener() : ":" + (cmd.CommandType == SystemCommandOption.Shutdown ? cmd.Args[0] :  cmd.Args[1])),
                    end.ToString()
                    );
           
       
            // broadcasting data over wire
            sender.Send(data, data.Length, end);
        }
        //UDP监听
        public BroadcastListener(CommandReceived callBack, int udpPort)
        {
          
            mCallBack = callBack;
           
            mListener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            IPEndPoint end = new IPEndPoint(IPAddress.Any, udpPort);
            mListener.Bind(end);

            IPHostEntry localMachineInfo = Dns.GetHostEntry(Dns.GetHostName());
            this.IpAddressAndPort = localMachineInfo.AddressList[0].ToString() + ":" + udpPort.ToString();
            string logMsg = string.Format("BroadcastListener started: {0}", this.IpAddressAndPort);
            Handler.LogHandler.Info(logMsg);
            Handler.LogHandler.Traffic(logMsg);
            Console.WriteLine(logMsg);
           
            StartReceive();
        }
[System.Diagnostics.DebuggerNonUserCodeAttribute]
        private void StartReceive()
        {
            #region Logging
            if (1 == Handler.Config.GetIntValueFromConfigByKey(Constants.ConfigLoggingEnable))
            {
                string msg = "[" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + "-" + System.Threading.Thread.CurrentThread.Name + "] Access Method: " + this.GetType().ToString() + "->" + ((object)MethodBase.GetCurrentMethod()).ToString() + " ;";
                Handler.LogHandler.Tracking(msg);
            }
            #endregion Logging
           
            byte[] buff = new byte[1024];
            mListener.BeginReceive(buff, 0, buff.Length, SocketFlags.None, new AsyncCallback(DataReceived), buff);
        }

        /// <summary>
        /// Datas the received.
        /// </summary>
        /// <param name="ar">A <see cref="T:System.IAsyncResult"/> Object.</param>
        private void DataReceived(IAsyncResult ar)
        {
            #region Logging
            if (1 == Handler.Config.GetIntValueFromConfigByKey(Constants.ConfigLoggingEnable))
            {
                string msg = "[ManagedThreadId: " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + "; CurrentThread.Name: " + System.Threading.Thread.CurrentThread.Name + "] Access Method: " + this.GetType().ToString() + "->" + ((object)MethodBase.GetCurrentMethod()).ToString() + " ;";
                Handler.LogHandler.Tracking(msg);
            }
            #endregion Logging
           
            try
            {
                byte[] buff = (byte[])ar.AsyncState;
                if (buff != null)
                {
                    AppCommand cmd = Translator.FromBinary(buff);
                    string trfMsg = string.Format("BroadcastListener::DataReceived is processing the following command: {0}" , cmd.CommandType.ToString());
                    // Handler.LogHandler.Info(trfMsg);
                    Handler.LogHandler.Traffic(trfMsg + Environment.NewLine + cmd.ToString());
                   
                    if (mCallBack != null)
                        mCallBack(cmd);
                    StartReceive();  //在异步进程中启动下下一次接受,因为StartReceive中会启动异步接收,StartReceive调用后立即返回,所以这里不算是递归。
                }
            }
            catch (Exception ex)
            {
                Handler.LogHandler.Fatal("[" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() +"-" +  System.Threading.Thread.CurrentThread.Name + "] - Error in DataReceived." + ex.Message, ex);
            }
        }
       
        case COM.IndexusMessage.ActionValue.Get:
                                {
                                    #region
                                    if (writeStats)
                                        Console.WriteLine("Message Action: {0}", msg.Action.ToString());

                                    Console.WriteLine("Search for Object with Key: {0}, Current Cache Size: {1}", msg.Data.Key, LocalCache.Amount());
                                    lock (bulkObject)
                                    {
                                        object objectFromCache = new byte[1] { 0 };

                                        objectFromCache = LocalCache.Get(msg.Data.Key);
                                        if (objectFromCache is byte[])
                                            Console.WriteLine("Key: {0} seems not to be available, Current Cache Size: {1}", msg.Data.Key, LocalCache.Amount());

                                        // send new object back to client within same
                                        // socket which contains the cache object.
                                        connection.Socket.Send(
                                            /*create new response message*/
                                            new COM.IndexusMessage(
                                            /*set same id*/
                                                msg.Id,

                                                COM.IndexusMessage.ActionValue.Successful,
                                                COM.IndexusMessage.StatusValue.Response,
                                                    new KeyValuePair<string, object>(
                                                    msg.Data.Key,
                                                    objectFromCache
                                                )
                                            ).GetBytes() /*serialize it*/
                                        );
                                    }
                                    break;
                                    #endregion
                                }
                            case COM.IndexusMessage.ActionValue.Remove:
                                {
                                    #region

                                    if (writeStats)
                                        Console.WriteLine("Message Action: {0}", msg.Action.ToString());

                                    Console.WriteLine("Remove Object with Key: {0}, current Cache amount: {1}", msg.Data.Key, LocalCache.Amount());
                                    lock (bulkObject)
                                    {
                                        // TODO: add a try / catch for each section!!!
                                        // remove it from the cache.   
                                        LocalCache.Remove(msg.Data.Key);

                                        // remove it from the cache cleaner job.
                                        this.expire.Expire.Remove(msg.Data.Key);
                                    }

                                    Console.WriteLine("New cache amount of object: {0}", LocalCache.Amount());

                                    #region rschuetz: MODIFIED: 21-07-2007: distribute object over wire to other installations
                                    // Question is if the client needs to wait until this happens,
                                    // or should the client first get an answer and just then it
                                    // will distribute it.
                                    if (this.enableServiceFamilyMode)
                                    {
                                        if (this.NetworkInstallationsAvailable())
                                        {
                                            ServiceLogic.NetworkDistribution.Replicate(replicationMessage);
                                        }
                                    }
                                    #endregion
                                   
                                    connection.Socket.Send(
                                            new COM.IndexusMessage(new Random().Next(),
                                            COM.IndexusMessage.ActionValue.Successful,
                                            COM.IndexusMessage.StatusValue.Response,
                                            new KeyValuePair<string, object>(string.Empty, new byte[1] { 0 })
                                        ).GetBytes()
                                     );

                                    break;
                                    #endregion
                                }