C#下用P2P技术实现点对点聊天

[文章信息]
作者: 王凯明
时间: 2003-03-13
P2P技术简介

  P2P,英文Peer-to-Peer的缩写,中译为对等互联或点对点技术。P2P技术可以让用户可以直接连接到其他用户的计算机,进行文件共享与交换,同时P2P在深度搜索、分布计算、协同工作等方面也大有用途。

  简单地说,P2P就是一种用于不同PC用户之间,不经过中继设备直接交换数据或服务的技术,它允许Internet用户直接使用对方的文件。每个人可以直接连接到其他用户的计算机,并进行文件的交换,而不需要连接到服务器上再进行浏览与下载。

  目前Internet的存储模式是"内容位于中心",而P2P技术的运用将使Internet上的内容向边缘移动。这将带来以下改变:

  首先,客户不再需要将文件上传到服务器,而只需要使用P2P与其他计算机进行共享;

  其次,使用P2P技术的计算机不需要固定的IP地址和永久的Internet连接,这使得占有极大比例的拨号上网用户也可以享受P2P带来的变革。

 实例介绍

  理解P2P技术的最好方法莫过于仔细观察并理解一个实际的P2P应用程序。C#作为微软.Net战略的重要棋子,对网络编程提供了很好的支持和优化。本文就通过一个程序,向大家介绍一下C#下的P2P编程的方法和实现机理。本文的这个程序不是很有用,但却很直观地给出了P2P(点对点)编程以及套接口编程的一些基本知识和概念。它是建立在TcpListener以及TcpClient这两个类基础上的。程序实现的原理也比较简单,但是用到了P2P技术重返"非中心化"的基本原则。简言之,用这个程序可以在网络中发送、接受消息,任何一台计算机既可以作为服务器端,又可以作为客户端。

  系统要求:

  1.Widows 2000服务器版操作系统或后续版本的操作系统。

  2.Visual Studio.net Framework正式版。

  具体方法:

  首先,打开VS.net,新建一个C#项目(注意:模板为Windows应用程序),不妨命名为"P2Pchat"。图示如下:

p2p-new.jpg

  其次,参照ICQ、OICQ等聊天工具,我们可以将程序的主界面布置成和常见聊天工具的消息发送对话框类似的布局。不过由于程序仅一个主界面,所以还要添加一些诸如"开始监听"、"停止监听"等控制按钮。同时,程序是支持昵称显示的。于是,按照这个思想,我们可以开始布置程序的主界面了。首先,往主界面上拖放如下一些控件:两个Label控件、三个Button控件、三个TextBox控件、一个RichTextBox控件以及一个StatusBar控件。

各个控件的属性设置如下表所示:

Form1 Text属性 P2P聊天工具
Label1 Text属性 目标计算机地址:
TestSlign属性 MiddleCenter
Label2 Text属性 昵称:
TextAlign属性 MiddleCenter
Button1 Text属性 开始监听
FlatStyle属性 Flat
Button2 Text属性 停止监听
FlatStyle属性 Flat
Enabled属性 False
Anchor属性 Top, Right
Button3 Text属性 发送消息
FlatStyle属性 Flat
Anchor属性 Top, Right
TextBox1 Text属性 (空)
Anchor属性 Top, Left, Right
TextBox2 Text属性 (空)
Multiline属性 True
Anchor属性 Top, Left, Right
TextBox3 Text属性 (空)
ForeColor属性 Firebrick
Anchor属性 Top, Left, Right
RichTextBox1 Text属性 (空)
ForeColor属性 Steelblue
ReadOnly属性 True
Anchor属性 Top, Bottom, Left, Right

  注:其中的Anchor属性是设置窗体上控件布局用的,当窗体大小改变后各个控件如何在窗体上重新分布由该属性决定,读者可参考更详细的介绍文章来理解。

  其他属性为默认即可,最终布置主窗体界面如下所示:

p2p-begin.jpg

  现在到了程序的主体部分,即代码部分。在给出代码之前,我想先向大家介绍一下实现的基本原理以及其中的一些逻辑关系。

 首先,程序运行后,用户得先按下“开始监听”按钮,按钮相应事件后,程序就进入了监听状态,状态栏有相应的显示。这样,本机就相当于“服务器/客户机”模式中的服务器了,其他计算机可以连接到本机并向本机发送消息。其他计算机通过该程序连接到本机是通过IP地址来实现的,C#对网络编程有很好的支持,所以程序员的工作量是比较小的。如此,一台计算机可以向另一台发送消息了。然而,这是个P2P程序,所以只要另一台计算机的用户也按下"开始监听"按钮,那台计算机也成了这台计算机的服务器了。于是就实现了消息互发功能,然而真正的服务器是不存在的,每台计算机都是服务器,每台计算机同时也是客户机,这就体现了P2P技术的"非中心化"原则。

  程序主要用到了一个Listen()函数和一个Send()函数。前者实现程序的监听功能,函数实现如下:

private void Listen()try
      
{
            tcpl 
= new TcpListener(5656); 
       tcpl.Start();
          statusBar1.Text 
= "正在监听"; 
             
while(listenerRun)
         
{
              Socket s 
= tcpl.AcceptSocket();
              Byte[] stream 
= new Byte[80];
               
int i=s.Receive(stream) ;
               
string message =
System.Text.Encoding.UTF8.GetString(stream);
             richTextBox1.AppendText(message);
            }

      }

    
catch(System.Security.SecurityException)
      
{
   MessageBox.Show(
"防火墙安全错误!","错误",
        MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
      }

    
catch(Exception)
        
{
          statusBar1.Text 
= "已停止监听!"
    }

}

  函数的主体是一个try-catch语句,try部分又是一个while循环,这表示只要用户不按"停止监听"按钮,程序就会一直处于监听状态。监听的端口是5656,这个端口是可以自己定义的,只要不跟常用的端口混淆就行了。一旦程序接收到远程计算机的一条消息,就将该消息添加到消息显示框中(消息显示框就是那个RichTextBox控件)。函数的catch部分是捕捉一些异常用的,如用户之间设置了防火墙,就不能彼此通讯了,或是对方已经停止监听了,那当然就不能向它发送消息了。另一个函数Send()是实现程序发送消息的功能的。函数实现如下:

private void Send()
{
     
try
       
{
           
string msg = "<"+textBox3.Text+">"+textBox2.Text;
          TcpClient tcpc 
= new TcpClient(textBox1.Text, 5656);
          NetworkStream tcpStream 
= tcpc.GetStream(); 
StreamWriter reqStreamW 
= new StreamWriter(tcpStream);
         reqStreamW.Write(msg);
           reqStreamW.Flush();
           tcpStream.Close();
           tcpc.Close();
        richTextBox1.AppendText(msg); 
          textBox2.Clear();
       }

       
catch(Exception)
        
{
             statusBar1.Text 
= "目标计算机拒绝连接请求!"; 
     }

}


  该函数的主体部分也是一个try-catch语句,它先根据用户的输入,建立一个和远程计算机的连接,注意其端口也为5656,而且必须是5656,这是为了和接收方端口保持一致,这样对方才能收到这里发送的消息。接着,函数根据用户在消息输入框中的内容以及用户的昵称向远程计算机发送消息。这样,只要网络无故障、远程计算机已经处于监听状态,它就能接收到这里发送的消息了。当然,这里处于监听状态了,远程的计算机也可以自如地往这里发消息。函数的catch部分也是用于捕捉一些异常的。

  同时还要注意的是,由于该程序用到了许多网络编程所需的对象以及输入输出对象,又运用了多线程编程机制,所以在程序的开始出得添加如下一些名字空间:

  using System.IO;
  
using System.Net.Sockets;
  
using System.Threading;

  最后,程序中各个控件的事件处理函数以及完整的代码请参看文后附带的源代码包。程序运行的图示如下:

p2p-run.jpg

  现在一个很基本的P2P运用程序以及完成,通过它,我们可以利用P2P技术的基本特性实现点对点通信。通过这个程序,我相信大家对C#下的P2P编程应该有了大致的了解。对于这个程序,不足的一点是功能比较简单,只可以发送、接受信息,而且不能穿过防火墙进行通讯,读者可以试着开发出功能更强P2P应用程序。

  总结

  最后,笔者希望能通过此文唤起大家对P2P技术的兴趣。因为P2P身后所蕴藏着的无比的创造力使人们对未来互联网充满了美好的憧憬,现在世界范围的P2P应用热潮也是一浪高过一浪。在可以预见的未来,随着对P2P研究的进一步深入和关注P2P的群体逐渐增多,P2P必将进入一个飞速发展的新时期。然而国内的P2P起步得比较晚,所以更需要有大量的技术研究投入以及足够的重视以赢得更好的发展。在此,笔者希望国内的P2P能取得辉煌的发展。

posted @ 2005-01-27 13:35 epan 阅读(10113) 评论(42)  编辑 收藏

 回复 引用   
#1楼2005-04-08 10:09 | fans--java
误人子弟,根本就不是什么p2p,全然一个c/s系统.你那东西不是“不能穿过防火墙进行通讯”,而是你完全不明白tcp/ip通信机理,你知道什么是防火墙吗?你用这同样的原理写一个访问一网站80端口的程序,看能不能联上。我可以明确告诉你是可以的,难道他就没有经过防火墙吗?象你这么写也就只能在同一局域网内用用啦!不懂就不要出来忽弄人。如还不明白的话,也很简单。只要你能实现一个广州的电脑(局域网本地ip192.168.0.2)和一北京电脑(局域网本地ip192.168.0.2)能直接通信不经第三方,注意两个ip是一样的不是我写错了,然后再来这里吹你的《C#下用P2P技术实现点对点聊天 》吧。极度藐视!
 回复 引用   
#2楼2005-04-08 14:27 | max[未注册用户]
我发现这个公告下面的时钟来自一个小日本的网站。???? !!!!
 回复 引用 查看   
#3楼[楼主]2005-04-09 00:14 | epan      
@fans--java

阁下定是高人,希望有机会看到你的杰作,也希望兄台不吝赐教,给我这些菜鸟上上课。期待~

 回复 引用   
#4楼2005-05-02 10:47 | 我晕倒[未注册用户]
我晕倒,只能说勇气可嘉
 回复 引用   
#5楼2005-05-21 15:34 | weaver
这也叫P2P,那真正的P2P又是什么,P2PP/
 回复 引用   
#6楼2005-06-10 11:02 | wywf
哇哇的,吐个不停
 回复 引用   
#7楼2005-06-10 11:12 | john
这确实不叫P2P...不是简单的每台机子又是客户机又是服务器就叫P2P了。
 回复 引用   
#8楼2005-08-19 11:32 | charlene[未注册用户]
不错,对初学者很有帮助,顶一下.我正想用c# tcpclient写一个局域的通讯程序,类似QQ的那种,你的文章对我是很有帮助的,谢谢.
 回复 引用   
#9楼2005-08-27 19:37 | 4545[未注册用户]
晕,,勇气可嘉

 回复 引用   
#10楼2005-08-28 14:31 | onlyuser[未注册用户]
啥JB玩意。
 回复 引用   
#11楼2005-08-31 11:45 | ss[未注册用户]
MD,比我还菜的人,毛都没长出来,就乱发贴。
 回复 引用   
#12楼2005-09-05 14:41 | lzh[未注册用户]
不要乱写, 误人子弟。
总不不写的好啊
 回复 引用   
#14楼2005-11-09 15:38 | 安放的[未注册用户]
在训别人的同时,是否应该把自己的东西写出来给大家看看!!!!!
 回复 引用   
#15楼2005-11-14 17:53 | icyfire[未注册用户]
什么也不说了~
楼主回去好好查阅一下资料

 回复 引用   
#16楼2005-11-15 20:46 | 帅个+冰[未注册用户]
泥沙比!!!
不懂问我呀!!!
QQ: 382330988
我很强!!!
不要乱说!!!!!!

 回复 引用 查看   
#17楼2005-11-23 21:25 | 编程人生      
好多声音,基于tcp/ip通信机理的聊天工具代码有吗,勇气可加
 回复 引用   
#18楼2005-12-21 20:40 | 孤魂影[未注册用户]
你有什么理由批评别人?你以为自己是谁 是 盖茨阿?人家好心好意教大家P2p原理,不领情就算了,还说三道四的,你们这些人啊,就是一辆空马车!!
 回复 引用   
#19楼2005-12-23 19:22 | 谭超[未注册用户]
我觉得很好阿,我是第一次接触这些东西,觉得对我这等初学者是很有帮助的。谢谢楼主了,加油阿,期待看到你的下一篇文章。
 回复 引用   
#20楼2006-01-12 15:32 | MJ[未注册用户]
楼主,你的这个文章只是简单的C/S模型,基于TCP协议的P2P的技术我也正在研究中,好多问题都不知道怎么解决~比如如何“吃掉”TCP连接失败的ICMP报文,希望楼主找到解决方法后给也给我发一份。
E-Mail : scmsmj@21cn.com

 回复 引用   
#21楼2006-03-01 10:14 | 路过[未注册用户]
确实,楼主还有好多东西要学习。
 回复 引用   
#22楼2006-03-31 16:39 | きん[未注册用户]
用C#.net 来编写点对点 适用于聊天还要用到什么控件
 回复 引用   
#23楼2006-08-09 15:14 | whoami[未注册用户]
要善于批评与自我批评
 回复 引用   
#24楼2006-10-17 12:50 | LiuYun[匿名]
勇气可嘉,就是题目有点离谱了点。能有勇气发贴就不要玫击了。各位高人应该把好的东西发下。不应该只会攻击那以后都没有发贴的人了。
 回复 引用   
#25楼2007-03-31 15:39 | 风扬蛮子[未注册用户]
不会吧,文不对题诶。这是路由可直通下的C/S通信,只不过加了双向而已。我也在搞这个,也许完成端口可以帮帮忙。有兴趣聊聊。
 回复 引用   
#26楼2007-08-15 12:37 | 学习[未注册用户]
学习 学习 再学习...

 回复 引用   
#27楼2008-01-16 19:30 | 无名名[未注册用户]
不错,文字挺工整的,不过,希望正式学一下计算机网络原理或者网络编程,再写一些技术性文章会好一点。


强,确实勇气可嘉!

 回复 引用 查看   
#28楼2008-01-31 15:37 | kkun      
无论如何,支持楼主!
这东西确实只能在局域网内使用,期待杰作
加油

 回复 引用   
#29楼2008-03-11 16:41 | moon_snake[未注册用户]
那些骂LZ的。你们既然那么牛X,怎么不写个来教教我们新手。
LZ,我顶你,对我们新手很有帮助。不管他是不是真正的P2P。

 回复 引用 查看   
#30楼2008-03-11 21:07 | moon_snake      
文章里说的资源包在哪啊?说文后有,怎么没找着,谁知道的说下。先谢谢了
 回复 引用   
#31楼2008-05-03 21:08 | sadfjhkwqeh[未注册用户]
asdffsdfasdsdadsa
 回复 引用   
#32楼2008-05-04 12:52 | 冈底斯[未注册用户]
要穿过不同的防火墙(或说NAT).可以用udp打洞技术..不过这需要一台公网IP的服务器..服务器只负责第一次中间握手...我最近在搞这个
 回复 引用   
#33楼2008-07-16 19:33 | jonllen[未注册用户]
晕>>>>>>>>>>!@#$%^&*()
给我搞死机了!

 回复 引用   
#34楼2008-07-19 11:37 | 鄙视[未注册用户]
在鄙视其他人的同时,你把你的东西拿出来看看,你那么牛你也拿出来给大家看看!就知道在那鄙视靠 我严重鄙视你
 回复 引用 查看   
#35楼2008-07-21 12:58 | KKcat      
一楼的哥们太过头了,都是学习的,何必呢。lz能写出来是强的,不过写这个标题是勇气可嘉。路漫漫其修远兮~
 回复 引用   
#36楼2008-07-29 08:53 | 浪费时间[未注册用户]
误人子弟
 回复 引用   
#37楼2008-08-21 19:35 | 老虎P2P[未注册用户]
我在学习P2P,但是你这个局域网内的这个也不会呢!希望赐教。这个程序你要是有做好的话希望你能发给我邮件一份!谢谢
我支持你!
我的MAIL:zycfmylove@163.com

嘎嘎,看来这个帖子怨气不小啊,走个过场,玩.Net下通讯的有兴趣的加我QQ79878172
 回复 引用 查看   
#39楼2009-03-30 08:37 | 报答      
还是学习为先
 回复 引用   
#40楼2009-04-18 18:36 | 顶楼主[未注册用户]
骂人的都是一群傻X
P2P中间还分很多中的 纯的P2P和混合的模式
动动你们的大脑想想看 如果没有服务器的支持可能聊天吗?

说LZ是C-S的人站出来 请问你见过有人把既做服务器又做客户机的终端叫C-S模式的吗?

唯一的办法就是在客户机中集成服务器功能

为什么要想得这么复杂 既然是P2P而不叫别的什么 那我们就简单的理解维点对点 既数据从一个点(终端)直接到另一个点 做到这个就可以了 你们还管别人如何实现的做什么?

多管闲事 这么多年了我也没看到除了这个例子以外的号称P2P的例子 有种你们去写啊

 回复 引用 查看   
#41楼2010-01-09 20:10 | hello-lee      
额 谢谢楼主。。。
 回复 引用 查看   
#42楼2012-01-15 19:49 | 石高飞      
引用きん:用C#.net 来编写点对点 适用于聊天还要用到什么控件

不是控件就OK的
这是一个典型的 只会 拖控件的 人 解决不了的问题

虽然看到最后博主的文章 确实让我大吃了一惊,不过,正如LS几位所说
精神可嘉。。。这一点 还是很不错的。