Beispiel #1
0
        public RPC(string ip, int port)
        {
            IPAddress  ipAddress  = IPAddress.Parse(ip);
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, port);

            this.socketPool = SocketPool.GetPool(ipEndPoint);
        }
Beispiel #2
0
        public static SocketPool GetPool(IPEndPoint ipEndPoint)
        {
            SocketPool pool;

            lock (_dic)
            {
                if (_dic.TryGetValue(ipEndPoint, out pool))
                {
                    return(pool);
                }

                pool = new SocketPool(ipEndPoint);

                _dic.Add(ipEndPoint, pool);
            }

            return(pool);
        }
Beispiel #3
0
        public void Send(ref Socket s, SMessage m, SocketPool socketPool)
        {
            byte[] head = GetBytes(m);

            if (head.Length > headSize)
            {
                throw new RPCException("Head 的 长度不能超过 " + headSize + " Byte , 注意 Header 值会进行 Url Encode , 中文字符经过 Url Encode 之后会变长 。");
            }



            //  如果 socketPool != null 表示是 客户端 在调用 Send() 方法 , 发生异常时需要创建新的 Socket 重新 Send()
            //  反之 , 则表示是 服务器端 在调用 Send() 方法 , 不需要重新 Send()

            if (socketPool != null)
            {
                //  这里的 try catch 是为了解决 服务器关闭连接 后 客户端 不知道 服务器连接 已关闭 的问题。
                //  客户端仍然从 SocketPool 中取出之前的 Socket 来使用 , 但因为服务器连接已经关闭,
                //  所以这个 Socket 是不能使用的,用了会报错,所以,这里在 catch 里会关闭已失效的 Socket ,
                //  并且新创建一个 Socket ,和 服务器建立新的连接,用新的 Socket 来 Send() ,
                //  返回到 RPC.Send() 方法后 , 这个新的 Socket 会被 Return 到 SocketPool 。
                //  所以这里的 Socket s 参数是 ref 参数 。 就是为了将 新的 Socket 返回到 RPC.Send() 方法 。
                //  正常来讲,服务器不会主动关闭连接,但在一些意外情况,比如服务器意外关闭时,服务器连接会意外关闭 。
                try
                {
                    s.Send(head);
                }
                catch
                {
                    socketPool.Close(s);

                    //  这里要特别先把 s = null; 是因为如果在 SocketPool.GetNew() 中出现异常,
                    //  没有成功的创建 新 Socket 赋值给 s , 则返回 RPC.Send() 方法后,会在 catch 中去关闭 s ,
                    //  但这个时候的 s 是在上面已经被关闭的 s ,于是会报“无法访问已释放的对象”的错误 。
                    s = null;

                    s = socketPool.GetNew();

                    s.Send(head);
                }
            }
            else
            {
                s.Send(head);
            }



            if (m.Content == null)
            {
                return;
            }


            byte[] b;

            int bufferSize;

            int sendCount;
            int readCount;

            long totalSendCount = 0;

            while (true)
            {
                bufferSize = totalSendCount + sendContentBufferSize <= m.ContentLength ?
                             sendContentBufferSize : (int)(m.ContentLength - totalSendCount);


                b = new byte[bufferSize];

                readCount = m.Content.Read(b, 0, bufferSize);

                sendCount = s.Send(b, 0, readCount, SocketFlags.None);

                totalSendCount += sendCount;

                if (totalSendCount >= m.ContentLength)
                {
                    break;
                }
            }



            //  如果 Send 的 Content 长度未达到 Content-Length 指定的长度 , 则发送 空字符 \0 来补齐
            //  直到达到 Content-Length 的长度

            long vacancyLength = m.ContentLength - totalSendCount;

            if (vacancyLength > 0)
            {
                SendVacancy(s, vacancyLength);
            }
        }