1

关于投票
转一篇TCP网络通信的好文——用C#实现基于TCP协议的网络通信

摘自CrossMan的专栏——用C#实现基于TCP协议的网络通讯

TCP协议是一个基本的网络协议,基本上所有的网络服务都是基于TCP协议的,如HTTP,FTP等等,所以要了解网络编程就必须了解基于TCP协议的编 程。然而TCP协议是一个庞杂的体系,要彻底的弄清楚它的实现不是一天两天的功夫,所幸的是在.net framework环境下,我们不必要去追究TCP协议底层的实现,一样可以很方便的编写出基于TCP协议进行网络通讯的程序。
  
  要进行基于TCP协议的网络通讯,首先必须建立同远程主机的连接,连接地址通常包括两部分——主机名和端口,如www.yesky.com:80中,www.yesky.com就是主机名,80指主机的80端口,当然,主机名也可以用IP地址代替。当连接建立之后,就可以使用这个连接去发送和接收数据包,TCP协议的作用就是保证这些数据包能到达终点并且能按照正确的顺序组装起来。
  
  在.net framework的类库(Class Library)中,提供了两个用于TCP网络通讯的类,分别是TcpClient和TcpListener。由其英文意义显而易见,TcpClient 类是基于TCP协议的客户端类,而TcpListener是服务器端,监听(Listen)客户端传来的连接请求。TcpClient类通过TCP协议与 服务器进行通讯并获取信息,它的内部封装了一个Socket类的实例,这个Socket对象被用来使用TCP协议向服务器请求和获取数据。因为与远程主机 的交互是以数据流的形式出现的,所以传输的数据可以使用.net framework中流处理技术读写。在我们下边的例子中,你可以看到使用NetworkStream类操作数据流的方法。
  
  在下面的例子中,我们将建立一个时间服务器,包括服务器端程序和客户端程序。服务器端监听客户端的连接请求,建立连接以后向客户端发送当前的系统时间。
  
  先运行服务器端程序,下面截图显示了服务器端程序运行的状况:
  
  
  
  然后运行客户端程序,客户端首先发送连接请求到服务器端,服务器端回应后发送当前时间到客户端,这是客户端程序的截图:
  
  
  
  发送完成后,服务器端继续等待下一次连接:
  
  
  
  通过这个例子我们可以了解TcpClient类的基本用法,要使用这个类,必须使用System.Net.Socket命名空间,本例用到的三个命名空间如下:
  
  using System;
  using System.Net.Sockets;
  using System.Text;//从字节数组中获取字符串时使用该命名空间中的类
  
  首先讨论一下客户端程序,开始我们必须初始化一个TcpClient类的实例:
  
  TcpClient client = new TcpClient(hostName, portNum);
  
  然后使用TcpClient类的GetStream()方法获取数据流,并且用它初始化一个NetworkStream类的实例:
  
  NetworkStream ns = client.GetStream();
  
  注意,当使用主机名和端口号初始化TcpClient类的实例时,直到跟服务器建立了连接,这个实例才算真正建立,程序才能往下执行。如果因为网络不通,服务器不存在,服务器端口未开放等等原因而不能连接,程序将抛出异常并且中断执行。
  
  建立数据流之后,我们可以使用NetworkStream类的Read()方法从流中读取数据,使用Write()方法向流中写入数据。读取数据时, 首先应该建立一个缓冲区,具体的说,就是建立一个byte型的数组用来存放从流中读取的数据。Read()方法的原型描述如下:
  
  public override int Read(in byte[] buffer,int offset,int size)
  
  buffer是缓冲数组,offset是数据(字节流)在缓冲数组中存放的开始位置,size是读取的字节数目,返回值是读取的字节数。在本例中,简单地使用该方法来读取服务器反馈的信息:
  
  byte[] bytes = new byte[1024];//建立缓冲区
  int bytesRead = ns.Read(bytes, 0, bytes.Length);//读取字节流
  
  然后显示到屏幕上:
  
  Console.WriteLine(Encoding.ASCII.GetString(bytes,0,bytesRead));
  
  最后不要忘记关闭连接:
  
  client.Close();
  
  下面是本例完整的程序清单:
  
  using System;
  using System.Net.Sockets;
  using System.Text;
  
  namespace TcpClientExample
  {
  public class TcpTimeClient
  {
  private const int portNum = 13;//服务器端口,可以随意修改
  private const string hostName = "127.0.0.1";//服务器地址,127.0.0.1指本机
  
  [STAThread]
  static void Main(string[] args)
  {
  try
  {
  Console.Write("Try to connect to "+hostName+":"+portNum.ToString()+"\r\n");
  TcpClient client = new TcpClient(hostName, portNum);
  NetworkStream ns = client.GetStream();
  byte[] bytes = new byte[1024];
  int bytesRead = ns.Read(bytes, 0, bytes.Length);
  
  Console.WriteLine(Encoding.ASCII.GetString(bytes,0,bytesRead));
  
  client.Close();
  Console.ReadLine();//由于是控制台程序,故为了清楚的看到结果,可以加上这句
  
  }
  catch (Exception e)
  {
  Console.WriteLine(e.ToString());
  }
  }
  }
  }
  
  上面这个例子清晰地演示了客户端程序的编写要点,下面我们讨论一下如何建立服务器程序。这个例子将使用TcpListener类,在13号端口监听,一旦有客户端连接,将立即向客户端发送当前服务器的时间信息。
  
  TcpListener的关键在于AcceptTcpClient()方法,该方法将检测端口是否有未处理的连接请求,如果有未处理的连接请求,该方 法将使服务器同客户端建立连接,并且返回一个TcpClient对象,通过这个对象的GetStream方法建立同客户端通讯的数据流。事实上, TcpListener类还提供一个更为灵活的方法AcceptSocket(),当然灵活的代价是复杂,对于比较简单的程序, AcceptTcpClient()已经足够用了。此外,TcpListener类提供Start()方法开始监听,提供Stop()方法停止监听。
  
  首先我们使用端口初始化一个TcpListener实例,并且开始在13端口监听:
  
  private const int portNum = 13;
  TcpListener listener = new TcpListener(portNum);
  listener.Start();//开始监听
  
  如果有未处理的连接请求,使用AcceptTcpClient方法进行处理,并且获取数据流:
  
  TcpClient client = listener.AcceptTcpClient();
  NetworkStream ns = client.GetStream();
  
  然后,获取本机时间,并保存在字节数组中,使用NetworkStream.Write()方法写入数据流,然后客户端就可以通过Read()方法从数据流中获取这段信息:
  
  byte[] byteTime = Encoding.ASCII.GetBytes(DateTime.Now.ToString());
  ns.Write(byteTime, 0, byteTime.Length);
  ns.Close();//不要忘记关闭数据流和连接
  client.Close();
  
  服务器端程序完整的程序清单如下:
  
  using System;
  using System.Net.Sockets;
  using System.Text;
  
  
  namespace TimeServer
  {
  class TimeServer
  {
  private const int portNum = 13;
  
  [STAThread]
  static void Main(string[] args)
  {
  bool done = false;
  TcpListener listener = new TcpListener(portNum);
  listener.Start();
  while (!done)
  {
  Console.Write("Waiting for connection...");
  TcpClient client = listener.AcceptTcpClient();
  
  Console.WriteLine("Connection accepted.");
  NetworkStream ns = client.GetStream();
  
  byte[] byteTime = Encoding.ASCII.GetBytes(DateTime.Now.ToString());
  
  try
  {
  ns.Write(byteTime, 0, byteTime.Length);
  ns.Close();
  client.Close();
  }
  catch (Exception e)
  {
  Console.WriteLine(e.ToString());
  }
  }
  
  listener.Stop();
  }
  }
  }
  
  把上面两段程序分别编译运行,OK,我们已经用C#实现了基于TCP协议的网络通讯,怎么样?很简单吧!
  
  使用上面介绍的基本方法,我们可以很容易的编写出一些很有用的程序,如FTP,电子邮件收发,点对点即时通讯等等,你甚至可以自己编制一个QQ来!
系统分类: 通信网络
用户分类: TCP/IP 以太网芯片
标签: TCP 网络通信 基于TCP .net framework
来源: 转贴
发表评论 阅读全文(95) | 回复(0)

3

关于投票
给EDN活动提点建议
 
    提点建议,EDN的活动我很支持,对大家有帮助,对EDN有好处,是个共赢互利的事情。

    只是觉得有一点,关于转帖的问题。无论在博客上还是论坛上,随意转 别人的贴而不写出处已经称为中国网络心照不宣的事情,长期,人们也将其看成很自然的事情。我不知道外国网络是什么样子,所以无权评价。但就事论事地说,我 心理觉得不太好受。

    开始我也是那种随便转帖的人,而且从没想过这样做有什么不妥。直到当我自己也写一些文章,经验,等等,并且想到网络这么大,我的一些很 有价值的文章,经验肯定早晚会被别人转去的。于是心里有一点点自私,毕竟是我花时间和精力做的东西,仅被别人Ctrl+C一下就成了别人的?而且还不注明 出处。又想,如果他注明了出处,我心里就平衡不少了。这时我意识到这样做是很不负责任的表现,是对别人劳动的不尊重。

    己所不欲,勿施于人。从此, 我转帖时开始注意到要加上出处。可能我有点自私,可能很多人很无私奉献。但是如果大家没有这样的习惯,就像盗版软件在中国的严重,已经影响到中国软件业的 发展一样,转帖不注出处也会影响到网络上好资料,有价值的文章的出现。其实很多有经验的人都会有些这样的心理吧,一些对自己很有价值,自己花了精力创作的东西不轻 易放在网上的。一般如果是可以卖的产品,都会拿出一小部分做一下宣传,然后在淘宝上卖云云。

    因此建议EDN在搞一些活动时能够加上一条规则:转帖要注明出处,否则无权参赛。不尊重别人劳动的人怎么能得到别人的尊重呢?以帮助大家养成尊重别人劳动的好习惯。否则,你这样转帖,会导致下一批网友也这样转帖;你不尊重别人,同时培养了一批不尊重你的人,结果是互相不尊重。一切交流,都是互相的。我们是希望生活在一个互相尊重的环境中呢,还是希望生活在一个互相不尊重的环境中呢?

    当然我们可以选择生活在互相不尊重的环境中,并且现在基本上就是这样的环境。我们也可以生活的很好,只要我们有足够的耐受力,能够看开这些,能够不把它当回事,能够接收这种不尊重,并且把它看成自己很大方,免费提供很多好东西,同时别人也要大方的对自己。这同样也是一种生活环境。可能我们生活在这种环境中久了,也就没感觉了。我们中华民族的确是耐受力很强的民族,对环境有着很强的适应力,这是优点,同时也是我们的缺点。

    希望能够引起大家的思考,对我们民族文化的一点思考。

    再次希望EDN再次搞活动时能够关注关于转帖不注出处的意见。我知道有很多人会反对我的观点。我们可以观点不同,可以意见达不成一致,但是我们可以交换各自的观点,让各自互相理解对方的意思。

——————————————————————————————————

    由此想到了一些相关的问题,再说说毕业论文。我不知道中国大学有多少学生是全部摘抄别人的,有多少是80%的摘抄,有多少是50%的摘抄,有多少20%的摘抄,又有多少完全是原创的。我只从郑强教授的演讲得知日本的大学的毕业论文(无论什么论文),好像没有“查资料”的概念,他们都是根据自己的研究得到的成果所做的论文。(当然学术理论是世界共享的)

    还听说(忘了在哪里听的了)澳大利亚的大学对论文抄袭现象管的非常严,说如果摘抄别人的字句超过两句话(还是多少个字,具体我忘了)就要注明出处;并且如果超过5句话(具体数字忘了)或一个段落的摘抄别人的文章就算是论文抄袭,直接没有成绩。

    当然现在我做不到毕业论文完全绝对的原创,还是要参考一些书籍和资料,我的习惯也不是一下就能改变的。但,就个人来讲,还是从一点一滴做起,从改变自己做起。我们管不了别人,只能管好自己,一辈子能学会管好自己就已经是件很不容易的事情了。

    君子穷则独善其身,达则兼济天下。修身齐家平天下,能做到第一样就很成功。孔子70才达到随心所欲不逾矩,长江后浪推前浪,相信自己的努力能够超过他老人家。
系统分类: 自由话题
用户分类: 生活
标签: 活动建议
来源: 原创
发表评论 阅读全文(378) | 回复(11)
总共 , 当前 /