赵工的个人空间


网络课堂部分转编程技巧部分转编程演练

 C#编程技巧

首页 > 网络课堂 > C#编程技巧 > C#网口TcpClient编程
C#网口TcpClient编程
现在,计算机联网已经普遍存在了,无论是通过插到RJ45插座的网线,还是通过WIFI无线上网,不能连接网络的计算机很难遇到,因此网络通信编程也很常用。计算机联网一般是通过TCP/IP,先建立一个连接,然后进行数据传输,C#编程有多种方式,使用TcpClient相对比较简单。
1)有效网卡的搜索:
在计算机中,联网要通过网卡,包括有线网卡和无线网卡两种,首先需要搜索到本机中的网卡及相关信息,然后让用户选择其中的某个网卡,再进行连接。
搜索计算机中存在的所有网卡,使用NetworkInterface.GetAllNetworkInterfaces()方法,返回是NetworkInterface数组,代码为:
  NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
不过,如果只是看得到的这些adapters名字,几乎都是一样的,似乎没有差别,需要通过相应的属性及方法来获取详细信息才能进行分辨。常用的属性及方法为:
  adapter.OperationalStatus   //获取网卡的工作状态,OperationalStatus.Up为正在使用的网卡
  adapter.NetworkInterfaceType  //获取网卡类型,Ethernet为以太网卡,Wireless80211为无线网卡,Loopback为软件环回
  adapter.Description  //获取网卡的说明信息,包括网卡厂商信息或驱动软件的一些信息
  adapter.Name  //获取网卡名,包括本地连接、以太网、WLAN、蓝牙网络连接等
  adapter.Speed  //获取网卡网速,一般需要除以1000000得到MB为单位的值
  adapter.GetPhysicalAddress()  //获取网卡物理地址,也就是MAC地址
  adapter.GetIPProperties().UnicastAddresses[adapter.GetIPProperties().UnicastAddresses.Count - 1].Address   //获取网卡的IPv4网址
  adapter.GetIPProperties().UnicastAddresses[adapter.GetIPProperties().UnicastAddresses.Count - 1].IPv4Mask   //获取网卡的IPv4掩码
  adapter.GetIPProperties().DnsAddresses[adapter.DnsAddresses.Count - 1]   //获取网卡的Dns地址
  adapter.GetIPProperties().GatewayAddresses[adapter.GatewayAddresses.Count - 1].Address.   //获取网卡连接网络的网关地址
  adapter.GetIPProperties().DhcpServerAddresses.Count   //值为1表示使用DHCP获得的动态网址,为0则为静态网址

当然,相关属性和方法还有一些,不过通过以上所列就能进行判断处理了。
计算机中网卡往往会有多个,还有一些可动态连接的,比如USB-Ethernet或USB-WIFI网口模块等,可以通过OperationalStatus属性来判断,只有属性为OperationalStatus.Up才有效。而软件环回可以通过IPv4网址为127.0.0.1来分辨。
可把获取得到的有效的网卡信息显示在一个下拉列表中,以供用户选择,比如选择使用有线的Ethernet连接,或者使用无线的WIFI连接,后面的处理都是一致的。
2)网络通信连接:
网络连接,要设置连接对端的IP地址及端口号,使用TcpClient方式连接时,连接对端应为Tcp Server,可以接受客户端client的接入请求并建立起一个连接,实现数据传输。
  byte[] rcvBuf = new byte[1024];
  TcpClient client = new TcpClient();
  client.Connect(sIP, port);
  NetworkStream ns = client.GetStream();
  ns.BeginRead(rcvBuf, 0, rcvBuf.Length, NetDataReceived, null);

上述代码中,先创建一个TcpClient实例,继而使用Connect()方法连接Tcp Server,其中sIP和port即为Tcp Server的IP地址及端口号,可以通过在界面中手动输入获取。然后使用GetStream()方法获取一个NetworkStream,下面就可以使用NetworkStream的读写方法来收发数据了。
因为以上网络连接过程中有可能出现异常,因此上述代码需要放入try-catch结构中。
代码中创建TcpClient实例使用了不带参数的构造函数,让计算机系统自动处理。也可以使用带参数的构造函数:
  IPEndPoint local = new IPEndPoint(IPAddress.Parse(localIP), localPort);
  client = new TcpClient(local);

但这样需要先把本地IP地址字符串转换为IPAddress对象,并和端口号数值一起构造IPEndPoint对象,然后才能用来实例化TcpClient,相对比较繁琐。而且,有些Tcp Server要求每次连接使用不同的端口,这就需要查找本机的可用端口号,一般使用大于49152的数值,会增加很多代码。
3)网络接收数据:
上面代码中最后一行使用了ns.BeginRead()方法,这是一种异步读取网络数据的方式,其中注册了一个网络数据接收事件处理函数NetDataReceived:
  private void NetDataReceived(IAsyncResult ar)
  {
     try
     {
       int bytesRead;
       bytesRead = client.GetStream().EndRead(ar);
       if (bytesRead < 1)
       {
         return;
       }
       else
       {
         byte[] rcv = new byte[bytesRead];
         Array.Copy(rcvBuf, 0, rcv, 0, bytesRead);
         txtDataReceived.BeginInvoke(new delegateParam(UpdateTextBox), rcv);
       }
       ns.BeginRead(rcvBuf, 0, rcvBuf.Length, NetDataReceived, null);
     }
     catch (Exception ex) { }
  }

代码中,也是先获取可以读取到的数据字节数bytesRead,据此创建一个相应长度的字节数组rcv,把数据缓冲区rcvBuf中的数据用Array.Copy()方法存入字节数组rcv,然后使用委托方式把数据输出到显示窗口界面。代码最后再次使用ns.BeginRead()方法读取下一帧数据。
4)网络发送数据:
通过网络发送数据比较简单,直接使用NetworkStream的write()方法:
  ns.Write(byData, start, byData.Length);
  ns.Flush();

其中byData为待发送数据的字节数组,当然也可以使用write()方法直接发送普通字符串,要根据编码方式确定。
发送数据过程中也有可能出现异常,因此也需要使用try-catch结构。
4)关闭网络连接:
因为前面的代码中实例化了TcpClient,然后获取了NetworkStream对象,因此关闭网络连接时也需要对应的处理:
  try
  {
     if (ns != null) ns.Close();
     if (client != null) client.Close();
  }
  catch (Exception ex)
  {
     MessageBox.Show(ex.ToString());
  }

上述代码也需要在界面窗口关闭时运行,以便在程序退出时把网络连接也关闭,释放占用的资源。
Copyright@dwenzhao.cn All Rights Reserved   备案号:粤ICP备15026949号
联系邮箱:dwenzhao@163.com  QQ:1608288659