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