计算机网络实验二 TCPUDP网络编程(乞丐版)

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

UDP通信

实验内容

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

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

UDP****服务器端

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

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(),更直观地看见了服务器端的线程情况。

总结

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值