1、计算机网络第二次实验智能 1402 班 201408070221 李帅玲目录一 实验目的 .1二实验原理 .11.TCP 原理 .12.UDP 原理 2三实验步骤及分析 .31.实验实现流程 32.TCPClient 代码实现及说明: 43.TCPServer 代码及说明 .54.UDPClient 代码及说明 .65.UDPServer 代码及说明 76.问题回答 8四实验总结 .91. 发生的服务器二次运行错误解释: .92.关于 TCP 和 UDP 传输不同点的思考: .9一 实验目的1. 熟练掌握 UDP、TCP Client/Server 模式的通信原理、2. 实验内容如下:二实验原
2、理1.TCP 原理TCP 是一种面向连接的、可靠的传输层协议。面向连接是指一次正常的 TCP 传输需要通过在 TCP 客户端和 TCP 服务端建立特定的虚电路连接来完成,该过程通常被称为“三次握手” 。可靠性可以通过多种方法来提供保证(快速重传和回退 N 步) ,在这里我们关心的是数据序列和确认。一个 TCP 连接的套接字对包含四元组(本地 IP 地址,本地端口号,目的 IP 地址,目的端口号)一个套接字包含一个 IP 地址和一个端口号。服务器为了能对客户机程序发起的连接做出响应,必须在客户机程序试图发起连接之前,作为一个进程在系统中运行。客户机/服务器应用程序传输过程:当服务器进程运行时,客
3、户机进程可以向服务器发起一个 TCP 连接。在客户机程序中,通过创建一个套接字来完成。当客户机创建它的套接字时,它指定服务器进程的地址,即服务器的 IP 地址和进程的端口号。一旦在客户机程序中生成套接字,客户机的 TCP与服务器的 TCP 发起三次握手并建立一个 TCP 连接。这个三次握手发生在运输层,对于客户机程序和服务器程序是完全透明的。在三次握手期间,当服务器接受到客户机的套接字时,将为特定的客户机程序创建一个新的套接字。TCP 传输流程图:2.UDP 原理UDP 是面向报文的不可靠传输。UDP 是一种无连接的服务,即在两个进程间没有创建管道时所需的初始握手阶段。因为 UDP 没有管道,
4、所以当一个进程需要向另一个发送一批字节时,该发送进程需要为这批字节附上目的进程地址和目的端口号(TCP 传输的字节不需要) 。并且,该进程对于每批由发送进程所发送的字节都必须重复做。UDP 目的地址由二元组组成(目的 IP 地址,目的端口号) ,带有 IP 目的地址和端口号的批字节数据称为分组。UDP 提供了一种不可靠面向报文的服务模型,它尽力而为地向目的交付这批字节,但不保证这批字节的确能被交付。UDP 是面向报文的,是旨在发送方单次操作所发送的一批字节在接收方作为一个批次来交付,这与 TCP 的字节流语义形成对照。UDP 是尽力而为的,UDP 传输流程图:三实验步骤及分析1.实验实现流程客
5、户机/服务器应用程序使用面向连接的运输服务案例:(1)一台服务机从其标准输入(键盘)读取一行字符,并通过其套接字将该行发送到服务器。(2)服务器从其连接套接字读取一行字符。(3)服务器将该字符转换成大写。(4)服务器将修改后的行通过其连接套接字再回发给客户机。(5)客户机从其套接字中读取修改后的行,然后将该行在其标准输出(监视器)上打印出来。2.TCPClient 代码实现及说明:package shiyan2;import java.io.*;import .*;public class TCPClient public static void main(String argv) throw
6、s Exception/*参数说明* sentence 用户输入的发送到服务器的字符串* modifiedSentence 从服务器得到并发送到用户标准输出的字符串* inFromUser 输入流,连接到标准输入,键盘输入的字符流入它* inFromClient 输入流,连接到客户端套接字,从网络来的字符流入它;* outToServer 输出流,连接到套接字,客户端发送到网络的字符流入它* clientSocket 套接字,包含目的服务器IP地址和端口号*/String sentence;String modifiedSentence;/创建用户输入流BufferedReader inFro
7、mUser= new BufferedReader(new InputStreamReader(System.in);/通过套接字创建TCP连接,localhost为服务器主机名(此处服务器为本地主机),/客户端通过主机名获取主机IP地址,1234为端口号Socket clientSocket = new Socket(“localhost“,1234);/创建连接到套接字的输入输出流DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream();BufferedReader inFromSe
8、rver = new BufferedReader(new InputStreamReader(clientSocket.getInputStream();/从键盘读取字符串sentence = inFromUser.readLine();/将字符串输入输出流,字符经套接字流入TCP管道outToServer.writeBytes(sentence+n);/接收来自服务器的字符modifiedSentence = inFromServer.readLine();/字符输出到屏幕System.out.println(“From server:“+modifiedSentence);/关闭套接字,
9、同时关闭客户端和服务器之间的TCP连接(此时客户机的TCP向服务器的TCP发送一个挥手报文)clientSocket.close();3.TCPServer 代码及说明package shiyan2;import java.io.*;import .*;public class TCPServer public static void main(String argv) throws Exception/*参数说明* clientSentence 服务器接受客户端发送来的字符串* capitalizedSentence 转换成大写字母后的字符串* inFromClient 输入流,连接到套接字
10、,客户端发送过来的字符流入它* outToClient 输出流,连接到套接字,服务器发送给客户端的字符流入它* welcomeSocket 监听用的套接字,包含服务器端口号1234* connectionSocket 新套接字,用于与客户端 TCP建立连接,其端口号也为1234*/String clientSentence;String capitalizedSentence;/审查请求连接的用户端其TCP目的端口号是否为1234ServerSocket welcomeSocket = new ServerSocket(1234);while(true)/保证一次建立多次与客户端通信Socke
11、t connectionSocket = welcomeSocket.accept();/创建输入输出流BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream();DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream();clientSentence = inFromClient.readLine();capitalizedSent
12、ence=clientSentence.toUpperCase()+n;outToClient.writeBytes(capitalizedSentence);TCP运行结果:先运行TCPServer之后再运行TCPClient如图,客户端向服务器发送报文段“abcdef”后,服务器将字符转换成大写字母后再发送回来。4.UDPClient 代码及说明package shiyan2;import java.io.*;import .*;public class UDPClient public static void main(String argv) throws Exception/*参数说
13、明* inFromUser 输入流,连接到标准输入,键盘输入的字符流入它* clientSocket 套接字,包本地端口号* IPAddress 目的服务器IP 地址* sendData 客户端发送的字符串* receiveData 客户端接收的字符串* sentence 键盘输入的字符串* sendPacket 发送的数据报文(数据,数据长度,目的IP地址,目的端口号)* receivePacket 接收的数据报文(数据,数据长度)*/BufferedReader inFromUser= new BufferedReader(new InputStreamReader(System.in);
14、/DatagramSocket 类型,因为UDP 是面向报文的,不同于 TCP Socket类型的套接字/创建套接字,此处没有发起TCP连接,所以不需要把服务器主机名或端口号作为参数/此种方式,运输层将自动为该套接字分配一个端口号,但不会给服务器自动分配一个套接字DatagramSocket clientSocket = new DatagramSocket();/此种方式,设置客户端端口号为5432/DatagramSocket clientSocket = new DatagramSocket(5432);/获取服务器IP地址InetAddress IPAddress = InetAddr
15、ess.getByName(“localhost“);/创建发送和接受字符串参数byte sendData = new byte1024;byte receiveData = new byte1024;/读取键盘输入的字符串并存入字符数组String sentence = inFromUser.readLine();sendData = sentence.getBytes();/构造数据报文(数据,数据长度,目的IP地址,目的端口号)DatagramPacket sendPacket=new DatagramPacket(sendData,sendData.length,IPAddress,2
16、345);/通过套接字发送数据报文clientSocket.send(sendPacket);/创建接收服务器发送来的数据的参数DatagramPacket receivePacket=new DatagramPacket(receiveData,receiveData.length);/通过套接字接收数据分组并存放到receivePacketclientSocket.receive(receivePacket);/转换成字符串并输出String modifiedSentence=new String(receivePacket.getData();System.out.println(“fr
17、om server:“+modifiedSentence);/关闭套接字,无需向服务器发送运输层报文clientSocket.close();5.UDPServer 代码及说明package shiyan2;import java.io.*;import .*;public class UDPServer public static void main(String argv) throws Exception/*参数说明* serverSocket 套接字,包含端口号* sendData 发送的字符串* receiveData 接收的字符串* receivePacket 获取的数据报文(数据
18、,数据长度)* sentence 从数据报文中拆分出的字符串* IPAddress 从数据报文中拆分出客户端的IP地址* port 从数据报文中拆分出的客户端的端口号,客户端与服务器的端口号是不同的* capitalizedSentence 将字符串转换成大写字母*/套接字,服务器端口号为2345DatagramSocket serverSocket = new DatagramSocket(2345);byte sendData = new byte1024;byte receiveData = new byte1024;while(true);/获取数据报文DatagramPacket r
19、eceivePacket=new DatagramPacket(receiveData,receiveData.length);serverSocket.receive(receivePacket);/拆分数据报文String sentence=new String(receivePacket.getData();InetAddress IPAddress = receivePacket.getAddress();int port=receivePacket.getPort();/字符转换成大写字母String capitalizedSentence=sentence.toUpperCase(
20、);sendData = capitalizedSentence.getBytes();/发送数据报文,没有建立连接所以需要知道客户端IP 和端口号DatagramPacket sendPacket=new DatagramPacket(sendData,sendData.length,IPAddress,port);serverSocket.send(sendPacket);UDP运行结果:同样先运行UDPServer.java 再运行UDPClient.java结果如图,服务器发回的数据后面那串符号,应该是我软件的问题。6.问题回答24.a 如果在运行 TCPServer 之前运行 TCP
21、Client,则客户端发送的请求将没有回应,因为服务器为了能够欧接收并回答客户的报文,它必须准备好并已经在运行,而先运行 TCPClient服务器还没有准备好。24.b 与上述同理。24.c 如果使用了客户端和服务器端使用了不同端口,则 TCP 客户端在发送请求的时候会报错,即无法连接;而 UDP 客户端在发送请求的时候不会报错(因为它不需要与服务器建立连接) ,但是其请求将得不到处理。有意思的是,因为之前在本机运行了一个端口号为2347 的 TCP 服务器程序,而当我的 UDP 客户端的目的端口号也设置为 2347,而不是 UDP服务器的端口号 2345 时,UDP 的请求也得到了处理,估计
22、是它碰巧的和 TCP 的服务器建立了连接。2.5UDPClient 中使用 DatagramSocket clientSocket = new DatagramSocket(5432);代替 DatagramSocket clientSocket = new DatagramSocket();UDPServer 中不需要更改端口号,前面一行代码为创建客户端的套接字,其端口号为5432,而第二行代码只是为客户端创建套接字,但其端口号为运输层分配的默认端口号,无论哪种对服务器端套接字的创建没有影响:DatagramSocket serverSocket = new DatagramSocket(2
23、347);这只是它的端口号,而对于服务器发送的数据报文; DatagramPacket sendPacket=new DatagramPacket(sendData,sendData.length,IPAddress,port); 其中的客户端端口号 port 是从数据报文中拆分出来的,所以如果客户端的端口号变为周知端口号了,那么此处的端口号自然也会改变的。此时 UDPServer 的端口号为 2347,UDPClient 的端口号为5432,而变化之前,UDPServer 的端口号为 2347,UDPClient 的端口号为运输层默认的端口号。四实验总结1. 发生的服务器二次运行错误解释:通
24、信时两个进程之间好像有一条管道,这条管道一直保持,除非其中一个进程关闭它。此处因为服务器运行一次以后代码中是创立了多线程,即运行一次以后除非关闭程序,否则此服务器程序将会一直运行,否则如果再次运行此服务器程序,将会出现程序占用的报错。2.关于 TCP 和 UDP 传输不同点的思考:(1 ) TCP 是面向连接的而 UDP 是无连接的,TCP 发送的是数据流,而 UDP 发送的是数据块TCP 有两个套接字,一个是监听套接字,用于监听客户端发送的请求是否是面向本服务器的,另一个是传输套接字,是用于建立传输连接的,该套接字与客户端的套接字建立连接后,相当于在客户端和服务器之间建立了一个管道,两者通过
25、该管道源源不断的传输数据。所以 TCP 用户端至少有两个连接套接字的数据流,一个输出流用于将客户端的数据报文通过套接字输出到 TCP 通道,一个输入流,将管道的数据报文通过套接字输入给 TCP 客户端的。而 TCP 服务器同样也有一个输出流,将数据报文通过套接字进入管道发送给客户端,还有一个输入流,将管道的数据报文通过套接字输入进来。而 UDP 是没有建立连接的,所以 UDP 的服务器只有一个传输数据的套接字。而且客户端和服务器只是将数据报文分块发送而不是流的形式,而每发送一次客户端和服务器都需要将目的端口和目的 IP 地址封装到数据报文里,这是与 TCP 不同的地方,TCP建立连接以后普哦,服务器在发送数据报文的时候有就不要记录目的地址和端口,直接通过管道传输即可。UDP 的传输也只是尽力而为的传输,不保证数据一定能安全到达目的地。