TCP是Transmission Control Protocol(传输控制协议)的简称,是TCP/IP体系中面向连接的运输层协议,在网络中提供全双工的和可靠的服务。
TCP最主要的特点:
(1)是面向连接的传输层协议;
(2)每个TCP连接只能有两个端点,而且只能一对一通信,不能一点对多点直接通信。
(3)通过TCP连接传送的数据,能保证数据无差错、不丢失、不重复地准确到达接收方,并且保证各数据到达的顺序与数据发出的顺序相同。
(4)数据以字节流的方式传输。
(5)传输的数据无消息边界。
利用TCP开发应用程序时,.NET框架提供两种工作方式.
(1)同步工作方式
指利用TCP编写的程序执行到发送、接收或监听语句时,在未完成工作前不再继续往下执行,即处于阻塞状态,直到该语句完成相应的工作后才继续执行下一条语句;
(2)异步工作方式
异步工作方式是指程序执行到发送、接收或监听语句时,不论工作是否完成,都会继续往下执行。
例如:同步接收数据时,接收方执行到接收语句后将处于阻塞方式,只有接收到对方发来的数据后才继续执行下一条语句;而如果采用异步工作方式,则接收方在执行到接收语句后,无论是否接收到对方发来的数据,程序都继续往下执行。
思考:这里的同步TCP和异步TCP与线程同步异步是否概念是否相同?
回答:
(1)这里的同步TCP和异步TCP仅仅指工作方式,它和线程间的同步不是一个概念。
(2)线程间的同步指不同线程或其共享资源具有先后关联的关系,而同步TCP和异步TCP则仅仅指TCP编程中采用哪种工作方式,即是从执行到发送、接收或监听语句时,程序是否继续往下执行这个角度来说的。
TcpListener类与TcpClient类
TcpListener类与TcpClient类两个类均封装了底层的套接字,并分别提供了对套接字进一步封装后的同步和异步操作的方法,降低了TCP应用编程的难度。
TcpListener类用于侦听和接受传入的连接请求。
TcpClient类用于提供本地主机和远程主机的连接信息。
注意,TcpListener和TcpClient只支持标准协议编程。如果希望编写非标准协议的程序,只能使用套接字来实现。
TcpListener类
TcpLISTener类在System.Net.Socket命名空间下。
常用的构造函数有两种:TcpListener(IPEndPoint iep)
TcpListener(IPAddress localAddr, int port)
举例:
IPAddress ipAddress = Dns.Resolve("localhost").AddressList[0];
Try
{
TcpListener tcpListener = new TcpListener(ipAddress, 1326);
}
catch ( Exception e)
{
Console.WriteLine( e.ToString());
}
在同步工作方式下, TcpListener类常用的方法:
Start启动监听,构造函数为:public void Start([int backlog])参数backlog为请求队列的最大长度,即最多允许的的客户端请求连接个数;
Stop关闭TcpListener并停止监听请求,构造函数为:public void Stop();
AcceptSocket
在同步阻塞方式下获取并返回一个用来接收和发送数据的Socket对象,同时从传入的连接队列中移除该客户端的连接请求。
AcceptTcpClient在同步阻塞方式下获取并返回一个封装了Socket的TcpClient对象,同时从传入的连接队列中移除该客户端的连接请求。
TcpClient类
TcpClient类在System.Net.Socket命名空间下。
主要用于编写客户端程序,且需要直接利用构造函数创建TcpClient对象。而服务器端程序中是通过TcpListener对象的AcceptTcpClient方法得到TcpClient对象的,所以不需要使用TcpClient类的构造函数来创建TcpClient对象。
构造函数有四种重载形式
- TcpClient()
- TcpClient(AddressFamily family)
- TcpClient(IPEndPoint iep)
- TcpClient(string hostname,int port)
(1)TcpClient()
该构造函数创建一个默认的TcpClient对象,并自动分配本机(客户端)IP地址和端口号。利用此构造函数创建对象后,还必须调用Connect方法与服务器建立连接。
例如:
TcpClient tcpClient=new TcpClient();
tcpClient.Connect("www.abcd.com", 51888);
(2)TcpClient(AddressFamily family)
该构造函数创建的TcpClient对象也能自动分配本机(客户端)IP地址和端口号,但是使用AddressFamily枚举指定使用哪种网络协议。创建该对象后,必须调用Connect方法与服务器建立连接。
例如:
TcpClient tcpClient = new TcpClient(AddressFamily.InterNetwork);
tcpClient.Connect("www.abcd.com", 51888);
(3)TcpClient(IPEndPoint iep)
该构造函数的参数iep指定本机(客户端)IP地址与端口号。当客户端有一个以上的IP地址时,而且程序员希望直接指定使用的IP地址和端口号,可以使用这种方式。如果使用这种方式,必须调用Connect方法与服务器建立连接。例如:
IPAddress[] address = Dns.GetHostAddresses(Dns.GetHostName());
IPEndPoint iep = new IPEndPoint(address[0], 51888);
TcpClient tcpClient = new TcpClient(iep);
tcpClient.Connect("www.abcd.com", 51888);
(4)TcpClient(string hostname,int port)
这是使用最方便的一种构造函数。参数中的hostname表示要连接到的远程主机的DNS名,port表示要连接到的远程主机的端口号。该构造函数会自动分配最合适的本地主机IP地址和端口号,并对DNS进行解析,然后与远程主机建立连接。例如:
TcpClient tcpClient = new TcpClient("www.abcd.com", 51888);
它相当于:
TcpClient tcpClient = new TcpClient();
tcpClient Connect("www.abcd.com",51888);
TcpClient类的常用属性
TcpClient类的常用方法
TcpClient用法举例:
TcpClient tcpClient = new TcpClient();
tcpClient.Connect("contosoServer", 11000);
NetworkStream networkStream = tcpClient.GetStream();
networkStream.ReadTimeout = 10;
byte[] bytes = new byte[1024];
networkStream.Read(bytes, 0, 1024);
string data = Encoding.UTF8.GetString(bytes);
networkStream.Close();
tcpClient.Close();
不论是多么复杂的TCP应用程序,网络通信的最基本前提就是客户端要先和服务器建立TCP连接,然后才可以在此基础上相互传输数据。由于服务器需要同时为多个客户端服务,因此程序相对复杂一些。
在服务器端,程序员需要编写程序不断地监听客户端是否有连接请求,一旦接受了客户端连接请求,即能识别是哪个客户;而客户端与服务器连接则相对比较简单,只需要指定连接哪个服务器即可。一旦双方建立了连接并创建了对应的套接字,就可以相互传输数据了。在程序中,发送和接收数据的方法都是一样的,区别仅是方向不同。
编写服务器端程序的一般步骤为:
使用对套接字封装后的类,编写基于TCP的服务器端程序的
一般步骤为:
(1)创建一个TcpListener对象,然后调用该对象的Start方法在指定的端口进行监听。
(2)在单独的线程中,循环调用AcceptTcpClient方法接受客户端的连接请求,并根据该方法的返回的结果得到与该客户端对应的TcpClient对象。
(3)每得到一个新的TcpClient对象,就创建一个与该客户对应的线程,在线程中与对应的客户进行通信。
(4)根据传送信息的情况确定是否关闭与客户的连接。
编写客户端程序的一般步骤为:
使用对套接字封装后的类,编写基于TCP的客户端程序的一
般步骤如下:
(1)利用TcpClient的构造函数创建一个TcpClient对象。
(2)使用Connect方法与服务器建立连接。
(3)利用TcpClient对象的GetStream方法得到网络流,然后利用该网络流与服务器进行数据传输。
(4)创建一个线程监听指定的端口,循环接收并处理服务器发送过来的信息。
(5)完成工作后,向服务器发送关闭信息,并关闭与服务器的连接。