计算机网络实验二 TCP/UDP网络编程(乞丐版)

其实有现成的代码改一下就可以了,非要自己写,弄出了一堆错,最后只好用这一个乞丐版的了

UDP通信

实验内容

使用UDP通信协议完成socket通信编程,实现简单的服务器-客户端通信程序

 

UDP通信需要几个关键对象:DatagramSocket,DatagramPacket,在UDP通信中,传送的数据格式是数据报,在这里就是Datagram,Socket是一个门,在编程者的角度来看,很大一部分的工作都是在应用层来完成的,如果我们想要使用位于传输层的UDP/TCP协议功能,就需要一个接口连接当前的应用层和传输层,socket就是这个接口。在UDP通信中,通过DatagramSocket传递的数据类型是DatagramPacket,我们要把想要传递的内容放在这个里面。

 

UDP服务器端

这里的思路是把服务器端和客户端作为两个独立的工程单独运行,对于这里的服务器端,首先实例化一个DatagramSocket对象,监听9999端口,然后当我们打开DatagramPacket方法内部发现:

扫描二维码关注公众号,回复: 9997986 查看本文章

DatagramPacket的构造方法需要两个参数,一个是字节数组类型的参数,表示传送的内容,还有一个参数表示字节数组的长度,所以客户端要给我们发过来这样的内容,服务器端也需要准备一个字节数组用来承接内容。调用DatagramSocket的方法receive完成这个socket对应的数据接收,然后我们把内容中的字节数组转换为String类型,再输出出来看结果

UDP客户端

    同样地我们准备一个DatagramSocket,实例为对象,这里我们在调用DatagramSocket的connect方法时需要两个参数,分别为目标主机的ip和端口号,在这个方法中指明了ip和端口之后,就可以不在DatagramPacket中再指明目标了。

    这里使用了一个方法是InetAddress.getLocalHost().getHostAddress()方法,返回一个String类型的数据,是我们本机的ip地址,由于我们这里客户端和服务器端都在我自己的主机上,所以目的ip就是源端ip,然后我们调用connect方法,再将准备好的String类型数据转换为字节数组的类型,把这个字节数组类型的内容装到DatagramPacket中,在服务器中已经提到了,DatagramPacket的构造函数需要两个参数,就是内容字节数组以及数组长度,当我们完成了DatagramPacket的封装之后,调用DatagramSocket的send方法,就把这一个数据报发出去了。

 

实验效果

通过截图中的信息可以看到,在服务器的进程中,我们接收到了客户端发来的这句话,并且输出到了窗口中。

 

 

 

 

TCP通信

    TCP与UDP的不同在于通信的可靠性,这一点在课上已经讲过了,当用到工程中,最直观的不同点在于使用的Socket类发生了变化,当我们实现基于TCP的服务器端时,使用的是ServerSocket类,而客户端使用的则是Socket就可以了,具体实现过程如下:

 

单线程

TCP客户端

    这里要完成双方的通信过程,所以使用了输入输出流来完成,这里实例化了几个对象,用来完成对输入输出流中内容的读写,BufferedReader类型的in和input分别对应对客户端使用输入流System.in输入的对象的读取和对服务器端传送过来的输入流对象的读取。PrintWriter类型的对象out实现了对Socket中传送过来的内容中输出流内容的读取,后面同样用前面提到的方法获取到了本机的ip,将ip和端口号封装到了实例化的Socket对象中。

由于需要实现双方的信息交流,所以客户端和服务器端都使用了while(true)来不断地监听端口,同时完成了对控制台中输入流的读取、socket中输入流和输出流对象的读取,转换为string类型并输出出来

 

 

 

TCP服务器端(单线程)

        服务器端需要通过ServerSocket来实例化socket,也可以在这种双向通信的关系中用来区别双方的角色。通过一个实例化的Socket对象来监听ServerSocket对应的端口,当调用ServerSocket的accept方法监听到Socket的时候,进入到循环中,使用和客户端中提到的相同的方法获取到输入流、输出流对象,并输出出来。

 

 

实验效果

 

    客户端向服务器端发送了一条“hello”消息,然后接收到了来自服务器发来的“nihao”消息,又向服务器发送了一条“bye”消息

    服务器接收到了来自客户端的“hello”消息,然后回复了一条“nihao”消息,又接收到了来自客户端的“bye”消息。

 

服务器端多线程

Server主类

    将前面提到的服务器端进行了一定的修改,将处理部分放到了线程中完成,服务器的主类中,接收到了Socket对象之后就传入到线程中,在线程中进行后续的操作。

 

ServerThread

    这里使用了Java多线程方法,这部分原来曾经使用过,也没太深入了解过,这次实验中写了几次线程,其中有的失败版本会导致CPU资源完全被占用,这里只介绍可行的方法。

    在网上看到有的同学介绍Java中实现多线程可以使用两种方法,分别是继承(extends)Thread类,并重写其中的run方法或者是继承(implements)Runnable类,其实这两种本质上是一样的,当我们打开Thread的定义可以看到:

Thread继承自Runnable,两种方法的根源是一样的。

在ServerThread类中,我重写了构造函数,这样可以将线程中需要的socket对象传入类内部。

又重写了Thread的run方法,run方法定义了当我们的线程启动之后需要做些什么事情。

这里主要是把单线程的Server中循环的内容拿出来放到了线程中,不再赘述。

 

实验效果

1.

2.

3.

 

        可以看到这里我们分别启动了两次客户端程序,而服务器端一直在运行,所以接收到一个客户端就为这个客户端开启一个线程,并调用start方法开始线程。后面调用方法Thread.currentThread().getName(),更直观地看见了服务器端的线程情况。

 

总结

    这次实验做的效率比较低,主要是自己没做好准备,做了几个版本的多线程也出了比较多的问题,在网上查找了很多博客也没发现解决方法,最后实现了简单的功能,对于网络通信这里还需要好好理解,底层的函数、接口都还没完全理解,这些在考试、笔试、面试中都会被问到,后面还是要时间更好地理解。

发布了63 篇原创文章 · 获赞 15 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/LieberVater/article/details/90050728