《第10章TCP协议开发ppt课件》由会员分享,可在线阅读,更多相关《第10章TCP协议开发ppt课件(35页珍藏版)》请在金锄头文库上搜索。
1、第10章 TCP协议开发,10.1 相关概念 10.2 定义与获取主机信息 10.3 同步套接字编程 10.4 同步套接字开发举例简单聊天程序 10.5 使用TcpClient和TcpListener简化TCP编程 10.6 异步套接字编程 10.7 异步套接字开发举例,10.1 基本概念,基本概念(相关概念) 同步 发送方将数据包发送到网络上以后,不等接收方响应,就接着发送下一个数据包。 异步 发送方将数据包发送到网络上以后,等接收方做出响应后,才接着发送下一个数据包。,- 同步套接字 在通过Socket进行连接、接收、发送操作时,客户机或服务器会暂停当前工作,处于等待状态,即一直等到有数据
2、时才继续执行下面的语句。一般在阻塞方式下使用这种方式。可见,同步套接字适用于网络传输量不太大的情况。当网络传输量很大时,长时间的等待可能会让用户无法忍受。 - 异步套接字 在通过Socket进行连接、接收、发送操作时,客户机或服务器不会暂停当前工作,而是利用callback机制进行连接、接收和发送处理。异步套接字适用于需要在网络上进行大量数据传输的应用程序,比如有几万客户同时传输的情况。,10.2 定义与获取主机信息,定义主机对象 IPEndPoint类 IPAddress类 获取主机信息 Dns类中常用方法 Dns.GetHostName() Dns.GetHostByName(string
3、 hostname) Dns.GetHostByAddress(address) Dns.Resolve(),1.定义主机对象 IPEndPoint 类包含应用程序连接到主机上的服务所需的主机和端口信息。通过组合服务的主机 IP 地址和端口号,IPEndPoint 类形成到服务的连接点。 常用的方法原型: public IPEndPoint(IPAddress address, int port); 说明: address:IP地址 port:端口号 功能:初始化IPEndPoint类的实例。 用法举例: IPAddressmyServerIP=new IPAddress.Parse(“127
4、.0.0.1”); IPEndPoint myServer=new IPEndPoint(myServerIP,13);,2. 主机解析 程序实例Dns.Resolve()的使用 using System; using System.Net; public class TestFileStream static void Main() Console.Write(输入主机名或者IP地址:); string str=Console.ReadLine(); IPHostEntry host=Dns.Resolve(str); for(int i=0;ihost.AddressList.Length
5、;i+) Console.WriteLine(host.AddressListi.ToString(); Console.WriteLine(host.HostName); Console.ReadLine(); ,10.3 同步套接字编程,1.服务器端口绑定与监听 在服务器与客户机连接传输数据前,服务器需要做以下事情: 1) 创建一个套接字。 2) 创建本地IPEndPoint对象。 3) 使用Bind()方法将所创建的套接字与本地IPEndPoint 绑定。 4) 使用Listen()方法设置套接字为监听模式。 5) 使用Accept()方法接收客户端连接请求并为客户端创 建一个客户端套接
6、字。,实现方法 using System.Net; using System.Net.Sockets; IPAddress ip=IPAddress.Parse(127.0.0.1); IPEndPoint iep=new IPEndPoint(ip,6788); Socket socket=new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp); socket.Bind(iep); socket.Listen(10); /最多允许10个客户端同时连接 while(true) Socket clien
7、tSocket=socket.Accept(); ,2.客户端建立与服务器的连接 客户端在传送数据前,只需要做两件事: 1) 创建一个套接字。 2) 使用Socket类的Connect()方法将套接字与远程服务器地址相连。 IPAddress ip=IPAddress.Parse(202.196.101.246); /服务器IP IPEndPoint iep=new IPEndPoint(ip,6788); Socket socket=new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp); sock
8、et.Connect(iep);,3. 发送数据 (1)使用Socket类的Send()方法 (2)使用NetworkStream类的Write()方法。 注意: 不论是使用Send()方法或者使用Write()方法,都必须先将发送的数据转换为字节数组,然后使用Send()或Write()将数据发送出去。实际上,这个字节数组的数据并不是直接发送到远程机器上,而是发送到了TCP缓冲区中(该缓冲区默认大小为1024字节)。,(1)使用Socket类的Send()方法 对服务器端,可以使用客户端连接时创建的套接字发送数据,例如: byte bytes=new byte1024; string mes
9、sage=发送的数据; bytes=System.Text.Encoding.Unicode.GetBytes(message); clientSocket.Send(bytes,bytes.Length,SocketFlags.None); 对客户端,用法相似,区别只是创建的套接字不同。,(2)使用NetworkStream类的Write()方法 如果创建了NetworkStream对象,就可以直接使 用该对象发送数据,例如服务器端代码可能类 似于如下形式: NetworkStream netstream=new NetworkStream(clientSocket); string mes
10、sage=发送的数据; byte bytes=System.Text.Encoding.Unicode.GetBytes(message); netstream.Write(bytes,0,bytes.Length); 与套接字的Send()方法不同,NetworkStream 对象的Write()方法返回值为void 。,4.接收数据 与发送数据相似,接收数据的方法也有两种:使用 Socket类的Receive方法或者使用NetworkStream类的 Read方法,其用法与发送数据类似。例如: byte message=new byte1024; NetworkStream netstre
11、am=new NetworkStream(clientSocket); int len=netstream.Read(message,0,message.Length); 注意,Read()方法有一个整型的返回值,表明实际从TCP缓冲区中 读取了多少字节的数据,这是因为有可能TCP缓冲区还没有接收 到远程设备发送过来的指定长度的数据。,5.TCP协议的无消息边界问题 TCP协议的无消息边界问题 TCP协议是无消息边界的,即不能保证来自单个Send方法的数据能被单个Receive方法读取。 解决方法 发送固定长度的消息 将消息长度与消息一起发送 使用特殊标记分隔消息,10.4 简单聊天程序,服务
12、器端编程 创建windows应用程序项目TestSyncServer,设计画面如图所示 各控件属性参见表10-1,“开始监听”的Click事件代码。 private void buttonStart_Click(object sender, System.EventArgs e) this.buttonStart.Enabled=false; IPAddress ip=IPAddress.Parse(this.textBoxIP.Text); IPEndPoint server=new IPEndPoint(ip,Int32.Parse(this.textBoxPort.Text); sock
13、et=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); socket.Bind(server); socket.Listen(10); clientSocket=socket.Accept(); this.listBoxState.Items.Add(与客户 +clientSocket.RemoteEndPoint.ToString()+ 建立连接); thread=new Thread(new ThreadStart(AcceptMessage); thread.Start();,privat
14、e void AcceptMessage() while(true) tryNetworkStream netStream=new NetworkStream(clientSocket); byte datasize=new byte4;netStream.Read(datasize,0,4); int size=System.BitConverter.ToInt32(datasize,0); Byte message=new bytesize;int dataleft=size;int start=0;while(dataleft0) int recv=netStream.Read(mess
15、age,start,dataleft);start+=recv; dataleft-=recv; his.richTextBoxAccept.Rtf=System.Text.Encoding.Unicode.GetString(message);catchthis.listBoxState.Items.Add(与客户断开连接);break;,“停止监听”的Click事件代码。 private void buttonStop_Click(object sender, System.EventArgs e) this.buttonStart.Enabled=true; try socket.Shu
16、tdown(SocketShutdown.Both); socket.Close(); if(clientSocket.Connected) clientSocket.Close();thread.Abort(); catchMessageBox.Show(监听尚未开始,关闭无效!);,添加“发送信息”的Click事件代码。 private void buttonSend_Click(object sender, System.EventArgs e) string str=this.richTextBoxSend.Rtf;int i=str.Length; if(i=0)return; else/因为str为Unicode编码,每个字符占2字节,所以实际字节数应*2 i*=2;byte datasize=new byte4; datasize=System.BitConverter.GetBytes(i); byte sendbytes=System.Text.Encoding.Unicode.GetByte