Java基础day24笔记:TCP-上传图片|TCP-客户端并发
01-网络编程(TCP-上传图片)
我们看看客户端和服务端都需要做哪些事情~
客户端:
1,服务端点。
2,读取客户端已有的图片数据。
3,通过socket输出流将数据发给服务端。
4,读取服务端反馈信息。
5,关闭。
代码:

这段代码有一个小小的bug,我们需要加上一句:

服务端:

别忘了头文件哦:

运行结果:

02-网络编程(TCP-客户端并发上传图片)
上节的代码中,服务端有局限性。当A客户端连接上以后,被服务端获取到,服务端执行具体流程,这时B客户端连接的话,只有等待。因为服务端还没有处理完A客户端的请求,还没有循环回来执行下次accept方法,所以暂时获取不到B客户端对象。
那么为了可以让多个客户端同时并发访问服务端,那么服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。
如何定义线程呢?
只要明确了每一个客户端要在服务端执行的代码即可,将该代码存入run方法中。
代码:



运行:

可以接着上传,但是发现将前一个上传的文件覆盖了。
我们不希望它被覆盖掉,所以需要修改一下代码,给它定义一个不会重复的命名方式~
代码:

运行结果:


OK,服务端的这个小问题解决了。
客户端我们还需要做一些改动。

运行效果:

03-网络编程(TCP-客户端并发登录)
需求:

我们在user.txt这个文件中存入了用户名:

代码:

刚刚循环部分的语句还不够完善,我们将它完善一下:

好,继续:




运行:

超过三次后就不行了哦:

04-网络编程(浏览器客户端-自定义服务端)
我们已经写了那么多客户端、服务端的程序,我们发现,客户端、服务端无非就是基于网络应用的程序而已。像这样的程序,在我们现实生活中很多,比如浏览器就是标准的客户端。我们现在既能做客户端,又能做服务端,那我们能不能做一个服务端,让浏览器来访问呢?
接下来就演示一下客户端和服务端,客户端:浏览器,服务端:自定义。
代码:

运行效果:


我们看到,浏览器收到了自己服务端发来的数据。
其实,浏览器在向外发请求,它将这些请求发送到了某些主机的11000端口上了,这些端口接收到请求,就返回数据“客户端你好”,这些数据浏览器能够解析。
浏览器可厉害了呢,不光能够解析这个数据,还能够解析其他的呢:

看看效果:

这些数据都被浏览器解析啦。
客户端除了浏览器还有其他的~
我们再试一下,重新启动一次服务端:

再重新打开一个命令行面板,输入:

它也收到了数据:

介绍一下telnet,它是windows当中为我们提供的远程登录的工具,它可以去连接网络中的任意一台主机,在dos命令行下连接,连接完以后可以对这台主机进行命令式的配置。比如说玩网络的时候,里面有很多交换机和路由器,这些设备都是可以配置的,我们可以通过telnet命令连接过去,远程登录过去,这样我们本地就可以接收到路由器的配置。简言之,telnet可以理解为一个客户端软件。
05-网络编程(浏览器客户端-Tomcat服务端)
这节课我们来演示:
客户端:浏览器。
服务端:Tomcat服务器。
Tomcat我们没学过,但是它就是一个服务器软件,学没学过不重要。
它能提供服务,说明了里面封装了Server Socket,事实上它就是纯Java编写的软件,里面封装着Server Socket。
我们双击startup.bat启动,发现服务器用的是8080端口:

Tomcat有个好处就是,可以读取我们自定义的资源。
我们建立一个自己的网站,myweb,在其中写一个网页demo.html:


访问:

06-网络编程(自定义浏览器-Tomcat服务端)
上节课我们演示了浏览器和Tomcat服务器的特点,那么,我们已经学会了客户端服务端以后,我们能不能模拟浏览器的动作,像浏览器一样到Tomcat服务端去请求数据?
这时我们需要了解一下,浏览器在访问服务器的时候它发了什么数据,才能请求到服务器的资源。

运行:

访问11000端口:

我们发现,浏览器给服务端发送了一个消息:

这些就是HTTP的请求消息头。
浏览器和Tomcat虽然都是不同厂商制作的客户端和服务端,但是呢,它们都遵从了一些国际标准化的协议和规则。底层的传输规则都走的是TCP,应用层的协议HTTP是一个公共的传输规则。那么,浏览器厂商要想和不同的厂商进行数据的交互,他们都得先遵从这个规则才可以。
它是什么意思呢?我们来解释一下(为了解释更多内容,我们将GET后面的内容替换成了内容更多的情况):
浏览器首先向服务器发送了一个GET请求,这个GET请求是一种请求方式,它有自己的特点。它紧接着跟服务器说,
“我想要访问myweb/demo.html这个资源,我的协议是HTTP,版本是1.1。”

“嘿!服务器!虽然咱俩不是一个公司,但是我告诉你哦,咱们俩遵从同一个标准的协议/规则,我可以接收的数据有:flash、gif、......、QVOD。”

“我的语言是简体中文版。 ”

“我的压缩方式是gzip。”

一些用户信息:

“我要访问的是192.168.1.254这台主机的11000端口。”

连接:保持活动。

OK,内容解释完了,下面来一个比较全的地址的解释:
“我要访问192.168.1.254这台主机的11000端口下的myweb这个资源路径下的demo.html这个资源”

注意一下,请求数据头和请求数据体之间必定有一个空行隔开(这个是格式定义的标准,识别到空行后就表示前面的数据头结束了):

好了,浏览器发什么我们都知道了,接下来我们自定义一个客户端。
接下来演示:
客户端:自定义。
服务端:Tomcat服务器。
代码:

我们先用自己的浏览器客户端走一遍:

接下来用自己的客户端来试一下:

但是运行的时间有点长,怎么办呢?
我们修改一下Connection属性的内容:

Keep-Alive是保持连接,数据发送完了之后还在,一直在等着,而closed则是发完数据后就断开连接了。
这个不是很重要,我们看一下这次的消息头,和上次的不太一样,这个叫做HTTP应答消息头,是Tomcat服务器发过来的。
其中,200是响应状态码,代表成功,OK是200的描述信息。另外的信息有:Server是阿帕奇的、最后一次被修改的时间、文本类型、文本长度、时间、连接状态。
07-网络编程(自定义图形界面浏览器-Tomcat服务端)
刚刚我们已经做出了dos命令行,接下来是不是可以做一下图像界面呀?








运行:

这只是图形化界面,接下来我们要实现它的功能,在第一个对话框中输入地址,点击“转到”,可以转到相应的地址页面。实现方式就是要对地址进行字符串的分割,得到主机名、端口、资源路径、资源名等信息。
接下来我们对代码进行修改,将showDir这个函数中的代码全都删掉,我们重新写,先试着对地址进行字符串分割:

运行效果:

我们再进一步将主机名和端口号分割开:

接下来将之前的代码复制过来:

接上面蓝框中的:

对tf.addKeyListener事件和but.addActionListener事件进行修改:


再导入这个包:

但是运行出现了一些小问题,我们发现刚刚代码中有些需要修改的地方,在showDir这个函数中,1,加入清空动作:

2,将下面这句话注释掉:

3,在消息头后添加空行:

运行效果:

我们获取到了数据,只是解析不了里面的html代码。
浏览器强大就强大在它里面挂了n多的解析引擎,比如html解析引擎、cs解析引擎、javascript解析引擎,etc。
另一个问题就是,浏览器显示的数据只有html文档里的,而我们将响应头的信息也显示了。
浏览器是应用层的软件,我们做的这个软件走的是传输层,我们将传输层发过来的数据全拿过来了,而浏览器把有关于HTTP协议封装的信息拆掉了。我们知道,数据在向上传输到应用层的时候会拆包,它把这个包拆了,我们没拆了。下节课我们就要把它拆掉!
08-网络编程(URL-URLConnection)
我们来看一下URL这个类:

写一个URL地址,可以把它封装成对象:

下面我们演示一下URL对象,主要是试一下以下几个方法:

代码:

运行:

为什么getPath和getFile结果一样呢?而getQuery为null又是什么意思呢?
我们知道地址后面往往都会有些参数信息,比如这样:

OK,添加了参数信息之后我们再运行一下:

我们发现,getFile是带着参数信息的地址,getQuery拿到的则是参数信息。
我们平时在上网的时候输入的网址里都不会写端口的,所以我们将刚刚地址中的端口号删掉:

重新运行,当没有指定端口的时候,这个端口返回的就是-1:

下面讲一个我们必须要掌握的对象。

只要调用openConnection方法,就会去连接这台主机,获取主机的连接对象。
我们试着连接并打印一下返回的对象,打印结果中,显示了它对应的是http协议下的URL连接,目的地址也有:

好,现在连接到目的地址了,我们就可以将它的数据拿回来了。
代码:

运行,我们发现它没有响应头:

因为我们走的不再是传输层,而是应用层,应用层的http协议,把http协议所识别到的东西去掉了,返回了数据主体。
现在我们将刚刚的方法用到之前写的模拟浏览器可视化界面中,找到之前的代码,找到代码中showDir这个函数,只保留前两行代码,后面的都删掉:


记得将url改成urlPath,避免重名,后面写入我们这节课的新方法:

运行,发现响应头被拆掉啦:

都这里,除了有点遗憾不能进行解析,其他都没有问题。
URL中除了有openConnection方法,还有openStream方法,它可以直接开流:

我们看到其实它是两个步骤的缩写,所以用哪个都可以啦:

09-网络编程(小知识点)
我们在进行Socket对象的建立的时候,有一个不需要传递参数的空参数方法:

可是没有传入主机的话,它该连哪一个呢?
这个时候就会用connect方法去连接:

我们看看SocketAddress这个对象,发现它是一个抽象类:

我们看一下它的子类InetSocketAddress,发现它封装的是IP地址和端口:

下面再说说ServerSocket这个比较特殊的部分:

我们可以看到它的构造方法有:

其中有个参数叫backlog,它是什么意思呢?
点进去看看:

那么,队列的最大长度是什么意思呢?
它指的是,能同时连接到服务器的客户端的最大个数。
10-网络编程(域名解析)
接下来讲点比较重点的网络知识:我们在浏览器中输入某一个网址访问某一台主机的时候,它到底做了什么事情?
注意,这个必须要掌握喔。

我们知道,一般的网址并不是直接的ip地址,所以我们需要将它翻译成ip地址,也就是域名解析,这个时候要用到DNS服务器。
在这个面板中可以进行DNS服务器的配置:

这里的DNS服务器可以不配置,使用默认的,则是默认的电信/联通的服务器,当然也可以自己手动配置,但是如果我们在中国配置一个美国的DNS服务器,就太远了,可能在请求的这个过程中时间过长超时了。
接着讲下一个知识点,如下图,这两种方式都可以访问到目标页面:

因为127.0.0.1和localhost是有影射关系的,这个映射关系就在本机上,路径如上图,我们找到这个hosts文件:

哈哈,这里还有很多其他域名的映射,因为它们都是病毒网站,我们都映射到自己制定的ip地址上就不会被坑啦!
接下来我们玩一下,将localhost修改成myhost:

这时用myhost访问,成功:

一个地址可以起多个名字,我们再皮一下:

同样也成功:

接下来划重点:当我们在去访问主机的时候,其实它先找的是本地,本地没有才去外面找。
我们如果知道新浪的ip地址,并且把它写在host文件中,它就能直接在本地找到,就不用走DNS服务器了,相对而言提高了速度。
解析成功后,先看是什么协议,然后启动相应的协议,去解析后面的主机和端口,etc。
这是倒数第二天的课程了,还有最后一天等着你,加油,小楠楠~