zoukankan      html  css  js  c++  java
  • P2P通讯初步实现

    原文URL: http://www.cnblogs.com/dlwang2002/archive/2008/09/16/1291793.html

     

    1:基于Socket连接;

    2:在四个局域网内测试通过;

    3:简单模型,需要进一步优化效率和处理;

     

    ========================= 备注:   经过修改和重构,抽象出来的P2PLib已经可以工作了,并且提取出一个Envelope对象,当作通讯协议和数据载体。   在这个Lib之上,很容易实现不同局域网之间的具体应用,比如现在已经建立了三个应用:   1:IM,跨局域网即时通讯(UI像MSN)   2:FT,文件传输,断点续传   3:DP,数据库代理(客户需要在任何地方访问它局域网内的数据库,这一个其实是作为某ORM的数据层出现的。)
    ========================== 基本思路

    两个分别在不同的局域网内的用户无法直接建立连接并通讯。因为处在不同局域网的用户(没有公共IP)无法被外部机器主动连接,所以凡是所谓的P2P一般都是通过中间服务器中转通讯的。比如在几年前俺曾经介绍过一个P2P的软件,http://www.cnblogs.com/dlwang2002/archive/2005/04/14/207988.html,基本原理那里面有介绍。

    这次所建立的模型,是双方都在不同的局域网内部,都没有公用IP

    基本原理是这样的。局域网A内用户PA想要和局域网B内的用户PB通讯,那么需要通过中间服务器S进行转接通讯。Socket链接虽然只是由一方发起(局域网内的),但是socket确实一个可以在两端都能通讯的,也就是说,PA链接S后,S实际上可以使用这个通道直接发消息给PA。同理,如果PB连接之后,S将有两个Socket实例,然后S可以把SA的消息直接转发给SB,这样SB就转载了SA的请求到了PB。虽然还是要通过中转,但是S只负责把两端Socket互联,速度延时可近似认为是0,也就是可以认为PAPB是建立了直接的链接,P2P

    过程如下:

    1:)PAS发出连接请求;S接受请求,并且保留住PAsocket实例SA,存进一个在线用户列表LiveConnections

    2:)PB请求S并建立连接(和A无先后关系),S中保存其socket实例SB

    3:)PAs发出通讯请求,指明通讯对象是PB

    4:)S接收到A的请求,再当前的LiveConnections中找到PBsocket示例SB,转发消息;

    5:)PB接受到来自PA的消息。

     

     

    主要程序代码

       1:)首先的问题是如何建立Socket连接。这个问题在以前的一篇Blog中有提到(http://www.cnblogs.com/dlwang2002/archive/2008/07/21/924803.html)。这里使用的代码基本上都是和那一个一样的,只有中间处理通讯数据的部分稍有不同。这些代码不再赘述。

       2:)服务器S处理转发消息的代码

                     

     1     #region hander data 2                    try 3                    {  4                        Logger.Log("DataReceive", data);//test, catch the data transaction 5 6                        string[] allData = data.Split(';');  7                        string requestTo = allData[0]; // this is the basic format: to_IP;from_IP;MSG  8  9                        //find stored socket connection here10                        ClientConnection requectToCC = null; 11                        foreach (DictionaryEntry de in SocketListener.ClientConnections) 12                        { 13                            ClientConnection cc = de.Key as ClientConnection; 14                            // request form will be like this "xx.xx.xxx.xxx:xxxxxx",the last number is running number 15                            // so if 2 client both in the same network, this will be confued to dispatch the socket 16                            //here just find the last one that in the same network17                            if (cc.RequestFrom.IndexOf(requestTo) > -1) 18                            { 19                                requectToCC = cc; 20                            }21 22                        }23                        if (requectToCC != null && requectToCC.ConSocket.Connected) 24                        25                            //can get the connection here, then transfer this request to it26                            try27                            { 28                                ReplayMsg(requectToCC.ConSocket, data); 29                            }30                            catch (Exception ce) 31                            { 32                                ReplayMsg(this.ConSocket, "process error: " + ce.Message); 33                                Logger.Log("SendMsgError", ce.Message); 34                            }35                        }36                        else37                        { 38                            //if can not find, means the reqeust to is not login/register there39                            ReplayMsg(this.ConSocket, "the client you request to is disconnected"); 40                            Logger.Log("SendMsgError""the client you request to is disconnected"); 41                        }42                        // 43                    }44                    catch (Exception ex) 45                    { 46                        Logger.Log("DataError " + _requestFrom, ex.Message); 47                    }48                    #endregion

       3:)客户端的简单实现

     

     1 namespace P2PClient  2 {  3     public class ConnectionManager  4     {  5         private Socket _socket;  6         private IPEndPoint _hostEP;  7         private string _localIP;  8  9         public delegate void MessageReceiveEvent(string fromIP,string msg); 10 11         public event MessageReceiveEvent OnMsgReceived; 12 13         public ConnectionManager(string ip, int port) 14         { 15             IPAddress address = IPAddress.Parse(ip); 16             _hostEP = new IPEndPoint(address, port); 17         } 18 19         public bool Connect2Server() 20         { 21             try22             { 23                 _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 24                 _socket.Connect(_hostEP); 25 26                 IPHostEntry oIPHost = Dns.Resolve(Environment.MachineName); 27                 _localIP = oIPHost.AddressList[0].ToString(); 28 29                 //there use the same socket, to wait for reply msg30                 Thread thread = new Thread(new ThreadStart(WaitForReceiveData)); 31                 thread.Name = "connection_"; 32                 thread.Start(); 33 34                 return true; 35             } 36             catch (Exception ex) 37             { 38                 return false; 39             } 40         } 41         public void Close() 42         { 43             _socket.Shutdown(SocketShutdown.Both); 44             _socket.Close(); 45         } 46         public void SendMessage(string clientIP, string msg) 47         { 48             string sendStr = clientIP + ";"+_localIP+";" + msg;//simple format; to_IP;from_IP;MSG49 50             byte[] bytesSendStr = new byte[1024]; 51             bytesSendStr = Encoding.ASCII.GetBytes(sendStr); 52             _socket.Send(bytesSendStr, bytesSendStr.Length, 0); 53         } 54 55         public void WaitForReceiveData() 56         { 57             byte[] bytes = new Byte[1024]; 58 59             while (true) 60             { 61                 bytes = new byte[1024]; 62                 string data = ""; 63 64                 //the system while be wait here until there is msg received here65                 int bytesRec = this._socket.Receive(bytes); 66 67                 data += Encoding.ASCII.GetString(bytes, 0, bytesRec); 68                 #region hander data69                 Logger.Log("DataReceive", data); 70 71                 string[] allData = data.Split(';'); 72                 string requestFrom = allData[1]; // this is the basic format; to_IP;from_IP;MSG73                 string msg=allData[2]; 74 75                 if (OnMsgReceived != null) 76                 { 77                     OnMsgReceived(requestFrom, msg); 78                 } 79                 #endregion80             } 81         } 82 83 84     }
          4:)UI等其他处理 (略)

     

     

    问题

    1:)一个Socket的实例可以在服务器/客户端存活多久呢?我测试发现,至少几个小时没有问题,但是最长时间却不知道。

        2:)服务器S用单独的线程来处理链接,并不是最好的方式

        3:)服务器负载平衡,在多个服务器的情况下,要让客户端可以选择效率最高的服务器进行中转

        4:)有一台机器已经在公网上,或者两台都在公网上,需要另外的模型。他们不需要中转。

     

    小结

        简单,效率未知。 server.jpg client.jpg

     
     
     
     
  • 相关阅读:
    fedora上部署ASP.NET——(卡带式电脑跑.NET WEB服务器)
    SQL Server 请求失败或服务未及时响应。有关详细信息,请参见事件日志或其它适合的错误日志
    8086CPU的出栈(pop)和入栈(push) 都是以字为单位进行的
    FTP 服务搭建后不能访问问题解决
    指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配
    Linux 安装MongoDB 并设置防火墙,使用远程客户端访问
    svn Please execute the 'Cleanup' command. 问题解决
    .net 操作MongoDB 基础
    oracle 使用绑定变量极大的提升性能
    尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题。
  • 原文地址:https://www.cnblogs.com/systemnet123/p/3383870.html
Copyright © 2011-2022 走看看