1第5章TCP应用编程5.1TCP应用编程概述5.2利用同步TCP编写网络聊天程序5.3利用同步TCP编写网络游戏5.4异步TCP应用编程5.5异步TCP编程举例2第5章TCP应用编程(续)本章教学目的通过学习,使学生掌握涉及的知识点,能对TCP同步编程流程有深入认识,并熟悉异步TCP编程的基本概念和异步TCP应用编程的一般方法。本章教学要求(1)掌握TCP的特点、涉及到相关类、TCP应用编程的一般步骤以及怎样解决无消息边界问题;(2)掌握同步TCP编程的流程和使用方法。(3)掌握异步设计模式、异步TCP应用编程的一般方法。教学难点和重点TCP应用编程的一般步骤,如何开辟多线程与多个客户打交道,如何实现服务器和客户端相关功能。异步设计模式实现。35.1TCP应用编程概述5.1.1TCP简介5.1.2TcpListener类与TcpClient类5.1.3TCP应用编程的一般步骤5.1.4TCP的无消息边界问题45.1.1TCP简介TCP是TransmissionControlProtocol(传输控制协议)的简称,是TCP/IP体系中面向连接的运输层协议,在网络中提供全双工的和可靠的服务。TCP最主要的特点:(1)是面向连接的传输层协议;(2)每个TCP连接只能有两个端点,而且只能一对一通信,不能一点对多点直接通信。(3)通过TCP连接传送的数据,能保证数据无差错、不丢失、不重复地准确到达接收方,并且保证各数据到达的顺序与数据发出的顺序相同。(4)数据以字节流的方式传输。(5)传输的数据无消息边界。55.1.1TCP简介(续)利用TCP开发应用程序时,.NET框架提供两种工作方式.(1)同步工作方式指利用TCP编写的程序执行到发送、接收或监听语句时,在未完成工作前不再继续往下执行,即处于阻塞状态,直到该语句完成相应的工作后才继续执行下一条语句;(2)异步工作方式异步工作方式是指程序执行到发送、接收或监听语句时,不论工作是否完成,都会继续往下执行。例如:同步接收数据时,接收方执行到接收语句后将处于阻塞方式,只有接收到对方发来的数据后才继续执行下一条语句;而如果采用异步工作方式,则接收方在执行到接收语句后,无论是否接收到对方发来的数据,程序都继续往下执行。65.1.1TCP简介(续)思考:这里的同步TCP和异步TCP与线程同步异步是否概念是否相同?回答:(1)这里的同步TCP和异步TCP仅仅指工作方式,它和线程间的同步不是一个概念。(2)线程间的同步指不同线程或其共享资源具有先后关联的关系,而同步TCP和异步TCP则仅仅指TCP编程中采用哪种工作方式,即是从执行到发送、接收或监听语句时,程序是否继续往下执行这个角度来说的。75.1.2TcpListener类与TcpClient类TcpListener类与TcpClient类两个类均封装了底层的套接字,并分别提供了对套接字进一步封装后的同步和异步操作的方法,降低了TCP应用编程的难度。1.TcpListener类用于侦听和接受传入的连接请求。2.TcpClient类用于提供本地主机和远程主机的连接信息。注意,TcpListener和TcpClient只支持标准协议编程。如果希望编写非标准协议的程序,只能使用套接字来实现。85.1.2TcpListener类与TcpClient类(续)TcpListener类1.TcpLISTener类在System.Net.Socket命名空间下。2.常用的构造函数有两种:TcpListener(IPEndPointiep)TcpListener(IPAddresslocalAddr,intport)3.举例:IPAddressipAddress=Dns.Resolve(localhost).AddressList[0];Try{TcpListenertcpListener=newTcpListener(ipAddress,1326);}catch(Exceptione){Console.WriteLine(e.ToString());}95.1.2TcpListener类与TcpClient类(续)在同步工作方式下,TcpListener类常用的方法:1.Start启动监听,构造函数为:publicvoidStart([intbacklog])参数backlog为请求队列的最大长度,即最多允许的的客户端请求连接个数;2.Stop关闭TcpListener并停止监听请求,构造函数为:publicvoidStop();3.AcceptSocket在同步阻塞方式下获取并返回一个用来接收和发送数据的Socket对象,同时从传入的连接队列中移除该客户端的连接请求。4.AcceptTcpClient在同步阻塞方式下获取并返回一个封装了Socket的TcpClient对象,同时从传入的连接队列中移除该客户端的连接请求。105.1.2TcpListener类与TcpClient类(续)TcpClient类1.TcpClient类在System.Net.Socket命名空间下。2.主要用于编写客户端程序,且需要直接利用构造函数创建TcpClient对象。而服务器端程序中是通过TcpListener对象的AcceptTcpClient方法得到TcpClient对象的,所以不需要使用TcpClient类的构造函数来创建TcpClient对象。3.构造函数有四种重载形式①TcpClient()②TcpClient(AddressFamilyfamily)③TcpClient(IPEndPointiep)④TcpClient(stringhostname,intport)115.1.2TcpListener类与TcpClient类(续)(1)TcpClient()该构造函数创建一个默认的TcpClient对象,并自动分配本机(客户端)IP地址和端口号。利用此构造函数创建对象后,还必须调用Connect方法与服务器建立连接。例如:TcpClienttcpClient=newTcpClient();tcpClient.Connect();125.1.2TcpListener类与TcpClient类(续)(2)TcpClient(AddressFamilyfamily)该构造函数创建的TcpClient对象也能自动分配本机(客户端)IP地址和端口号,但是使用AddressFamily枚举指定使用哪种网络协议。创建该对象后,必须调用Connect方法与服务器建立连接。例如:TcpClienttcpClient=newTcpClient(AddressFamily.InterNetwork);tcpClient.Connect();135.1.2TcpListener类与TcpClient类(续)(3)TcpClient(IPEndPointiep)该构造函数的参数iep指定本机(客户端)IP地址与端口号。当客户端有一个以上的IP地址时,而且程序员希望直接指定使用的IP地址和端口号,可以使用这种方式。如果使用这种方式,必须调用Connect方法与服务器建立连接。例如:IPAddress[]address=Dns.GetHostAddresses(Dns.GetHostName());IPEndPointiep=newIPEndPoint(address[0],51888);TcpClienttcpClient=newTcpClient(iep);tcpClient.Connect();145.1.2TcpListener类与TcpClient类(续)(4)TcpClient(stringhostname,intport)这是使用最方便的一种构造函数。参数中的hostname表示要连接到的远程主机的DNS名,port表示要连接到的远程主机的端口号。该构造函数会自动分配最合适的本地主机IP地址和端口号,并对DNS进行解析,然后与远程主机建立连接。例如:TcpClienttcpClient=newTcpClient();它相当于:TcpClienttcpClient=newTcpClient();tcpClientConnect();155.1.2TcpListener类与TcpClient类(续)TcpClient类的常用属性属性含义Client获取或设置基础套接字LingerState获取或设置有关套接字逗留时间的时间NoDelay获取或设置一个值,该值在发送或接收缓冲区未满时禁用延迟(true禁用延迟,默认false)ReceiveBufferSize获取或设置接收缓冲区的大小(默认8192字节)ReceiveTimeout获取或设置套接字接收数据的超时时间(毫秒)SendBufferSize获取或设置发送缓冲区的大小(默认8192字节)SendTimeout获取或设置套接字发送数据的超时时间(毫秒)165.1.2TcpListener类与TcpClient类(续)TcpClient类的常用方法属性含义Close释放TcpClient实例,而不关闭基础连接Connect用指定的主机名和端口号将客户端连接到TCP主机BeginConnect开始一个对远程主机连接的异步请求EndConnect异步接受传入的连接尝试GetStream获取能够发送和接收数据的NetworkStream对象175.1.2TcpListener类与TcpClient类(续)TcpClient用法举例:TcpClienttcpClient=newTcpClient();tcpClient.Connect(contosoServer,11000);NetworkStreamnetworkStream=tcpClient.GetStream();networkStream.ReadTimeout=10;byte[]bytes=newbyte[1024];networkStream.Read(bytes,0,1024);stringdata=Encoding.UTF8.GetString(bytes);networkStream.Close();tcpClient.Close();185.1.3TCP应用编程的一般步骤不论是多么复杂的TCP应用程序,网络通信的最基本前提就是客户端要先和服务器建立TCP连接,然后才可以在此基础上相互传输数据。由于服务器需要同时为多个客户端服务,因此程序相对复杂一些。在服务器端,程序员需要编写程序不断地监听客户端是否有连接请求,一旦接受了客户端连接请求,即能识别是哪个客户;而客户端与服务器连接则相对比较简单,只需要指定连接哪个服务器即可。一旦双方建立了连接并创建了对应的套接字,就可以相互传输数据了。在程序中,发送和接收数据的方法都是一样的,区别仅是方向不同。195.1.3TCP应用编程的一般步骤(续)编写服务器端程序的一般步骤为:使用对套接字封装后的类,编写基于TCP的服务器端程序的一般步骤为:(1)创建一个TcpListener对象,然后调用该对象的Start方法在指定的端口进行监听。(2)在单独的线程中,循环调用AcceptTcpClient方法接受客户端的连接请求,并根据该方法的返回的结果得到与该客户端对应的TcpClient对象。(3)每得到一个新的TcpClient对象,就创建一个与该客户对应的线程,在线程中与对应的客户进行通信。(4)根据传送信息的情况确定是否关闭与客户的连接。205.1.3TCP应用编程的一般步骤(续)编写客户端程序的一般步骤为:使用对套接字封装后的类,编写基于TCP的客户端程序的一般步骤如下:(1)利用TcpClient的构造函数创建一个TcpClient对象。(2)使用Connect方法与服务器建立连接。(3)利用Tc