Asp.Net教程,WinForm教程,Asp.Net MVC,vs2008教程,vs2010教程,Silverlight技术,源码下载,Asp.Net视频教程
全站热门标签
vs2010 Silverlight 存储过程 水晶报表 ADO.NET JavaScript LINQ AjaxPro DataGridView 面向对象 Extjs GridView XML DevExpress HTML教程 Oracle jQuery 分页 GDI+ Visual C++2010 MySQL Office2010 WPF MVC Dojo WCF4.0 VB.NET Sql2005 textbox cookie WCF WinForm Discuz!NT SQL经典语句 T-SQL checkbox ASPxGridView F# asp.net SQL VS2008新特性 DropDownList Access TreeView Ajax VS2008 页面执行时间 Flex 字符串 回调 VB2005 DataSet C#时间 ASP.NET性能优化 用户在线检测 动画
FrameworkC#技术 VB.NET VC.NET WCF WPF
当前位置: 主页 > WinForm教程 > C#技术 >

P2P通讯初步实现(C# Socket连接)

时间:2010-08-31 23:35来源:未知 作者:admin 点击:
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,也就是可以认为PA和PB是建立了直接的链接,P2P。
过程如下:
1:)PA向S发出连接请求;S接受请求,并且保留住PA的socket实例SA,存进一个在线用户列表LiveConnections中
2:)PB请求S并建立连接(和A无先后关系),S中保存其socket实例SB
3:)PA向s发出通讯请求,指明通讯对象是PB
4:)S接收到A的请求,再当前的LiveConnections中找到PB的socket示例SB,转发消息;
5:)PB接受到来自PA的消息。
 
 
主要程序代码
   1:)首先的问题是如何建立Socket连接。这个问题在以前的一篇Blog中有提到(http://www.cnblogs.com/dlwang2002/archive/2008/07/21/924803.html)。这里使用的代码基本上都是和那一个一样的,只有中间处理通讯数据的部分稍有不同。这些代码不再赘述。
   2:)服务器S处理转发消息的代码

 

  hander data#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 here
10                        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 network
17                            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 it
26                            try
27                            {
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                        else
37                        {
38                            //if can not find, means the reqeust to is not login/register there
39                            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             try
22             {
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 msg
30                 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;MSG
49
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 here
65                 int bytesRec = this._socket.Receive(bytes);
66
67                 data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
68                 #region hander data
69                 Logger.Log("DataReceive", data);
70
71                 string[] allData = data.Split(';');
72                 string requestFrom = allData[1]; // this is the basic format; to_IP;from_IP;MSG
73                 string msg=allData[2];
74
75                 if (OnMsgReceived != null)
76                 {
77                     OnMsgReceived(requestFrom, msg);
78                 }
79                 #endregion
80             }
81         }
82   }
4:)UI等其他处理 (略)

 
问题
1:)一个Socket的实例可以在服务器/客户端存活多久呢?我测试发现,至少几个小时没有问题,但是最长时间却不知道。
    2:)服务器S用单独的线程来处理链接,并不是最好的方式
    3:)服务器负载平衡,在多个服务器的情况下,要让客户端可以选择效率最高的服务器进行中转
    4:)有一台机器已经在公网上,或者两台都在公网上,需要另外的模型。他们不需要中转。
 
小结
    简单,效率未知。
 

 

 
(责任编辑:admin)
Tags:Socket
责任编辑:admin
返回顶部
------分隔线----------------------------
推荐内容
骆驼户外男 真皮磨砂日常休闲鞋 低帮 2011秋冬新款 专柜正品特价 骆驼户外男 真皮磨砂日常休闲鞋 低帮 2011秋冬新款 专柜正品特价