网络编程
网络编程的常识------------------------------
目前主流的网络通讯软件有:微信、QQ、飞信、阿里旺旺、陌陌、探探、…
七层网络模型------------------------------
OSI(Open System Interconnect),即开放式系统互联,是ISO(国际标准化组织)组织在1985年研究的网络互连模型
OSI七层模型和TCP/IP五层模型的划分如下
当发送数据时,需要对发送的内容按照上述七层模型进行层层加包后发送出去
当接收数据时,需要对接收的内容按照上述七层模型相反的次序层层拆包并显示出来
如买手机时要包装手机,而我们接受时要拆包装而得到手机,即可以将手机看成一种数据,来形容这七层模型
相关的协议------------------------------
计算机在网络中实现通信就必须有一些约定或者规则,这种约定和规则就叫做通信协议
这样的协议就是:当你没有与别人进行通话时,即自言自语,那么就不需要一些规范
而当你要和别人通话时,需要将你的话让别人听的懂
就如英语一样,有规则,这样就需要在网络上也要有一种规则,使得都可以通话
例如:网络中一个微机用户和一个大型主机的操作员进行通信
由于这两个数据终端所用字符集不同,因此操作员所输入的命令彼此不认识
为了能进行通信,规定每个终端都要将各自字符集中的字符先变换为标准字符集的字符后,才进入网络传送
到达目的终端之后,再变换为该终端字符集的字符。对于不相容终端,除了需变换字符集字符外还需转换其他特性
通信协议可以对速率、传输代码、代码结构、传输控制步骤、出错控制等制定统一的标准
对于下面的协议了解即可,如果你不需要观看,可以直接的全局搜索"IP地址"即可,从那里开始
TCP协议------------------------------
传输控制协议(Transmission Control Protocol),是一种面向连接的协议,类似于打电话
建立连接 => 进行通信 => 断开连接在传输前采用"三次握手"方式
三次握手理解:客户端A,服务端B
主要是必须确认自己的接收能力和发送能力的可行
第一次:A先向B发送报文,确认自己和B的接收和发送能力是否可以(我的发送是否被B得到)
第二次:B收到A的报文,那么B就知道自己的接收能力和A的发送能力是可以的(B得到了A的发送)
并向A发送报文,确认自己的发送能力和A的接收能力是否可以(我的发送是否被A得到)
第三次:A收到B的报文
那么就知道自己的发送能力和接收能力都可以,且知道B的发送能力和接收能力都可以(我的发送已经被B得到,并回应了我)
并向B发送报文,自己的接收能力和你的发送能力都可以(给回应)
然后B收到后,就确认了自己和A的接收和发送能力都可以(确认A得到了B的发送)
那么就可以进行通信了
也可以用实例说明
例如:你首先向妹子招手,妹子看到你向自己招手后,向你点了点头挤出了一个微笑(你的发送被妹子得到)
你看到妹子微笑后确认了妹子成功辨认出了自己
但是妹子有点不好意思,向楼下和楼上看了一看,有没有可能你是在看别人呢,她也需要确认一下
妹子也向你招了招手(妹子的发送是否被你得到)
你看到妹子向自己招手后知道对方是在寻求自己的确认,于是也点了点头挤出了微笑
你知道了你和妹子的发送和接收都可以
妹子看到对方的微笑后确认了你就是在向自己打招呼(确认你得到了妹子的发送)
妹子知道了妹子和你的发送和接收都可以
即第一次和第二次握手确认了A的发送和接收都没错
第二次和第三次握手确认了B的发送和接收都没错
第二次握手可以看成两个握手,即A->B,B->A,A确认是B(确认A的接收和发送能力可以)
再B->A,A->B,B确认是A发送消息给他(确认B的接收和发送能力可以)
即这三次握手可以看成四个握手,只不过中间两次合并为一起了
客户端:在web中是以request对象存在的,发送请求给服务器端处理
服务端:顾名思义是服务的,客户端发送的请求交给服务器端处理,是以response对象存在,服务器端处理完毕后反馈给客户端
一般我们访问网站,都是客户端(浏览器、app)发出请求,然后对方服务器端(sina,sohu)响应
结果就是返回了页面路径给我们,我们再根据路径看到了网页
在通信的整个过程中全程保持连接,形成数据传输通道
保证了数据传输的可靠性和有序性
是一种全双工的字节流通信方式,可以进行大数据量的传输
传输完毕后需要释放已建立的连接,发送数据的效率比较低
UDP协议------------------------------
用户数据报协议(User Datagram Protocol),是一种非面向连接的协议,类似于写信
在通信的整个过程中不需要保持连接,其实是不需要建立连接
不保证数据传输的可靠性和有序性
是一种全双工的数据报通信方式,每个数据报的大小限制在64K内
发送数据完毕后无需释放资源,开销小,发送数据的效率比较高,速度快
三次握手,保证连接的可靠性
四次挥手,断开连接
四次挥手理解:客户端A,服务端B
第一次挥手:A向B发送消息,我要断开了
第二次挥手:B收到A的消息后,准备断开
第三次挥手:B向A发送消息,我断开了
第四次挥手:A向B发送消息,知道了
第一次握手: 客户端发送SYN包( seq= x) 到服务器,并进入SYN_SEND) ( 请求连接) 状态,等待服务器确认
第二次握手: 服务器收到SYN包,必须确认客户的ack= x+ 1 ,同时自己也发送一个SYN包( seq= y) ,即SYN+ ACK包
此时服务器进入SYN_RECV ( 半连接) 状态
第三次握手: 客户端收到服务器的SYN+ ACK包,向服务器发送确认包ack= y+ 1 ,此包发送完毕,客户端和服务器进入
ESTABLISHED ( 连接已建立) 状态,完成三次握手
SYN报文,seq初始序列号,ack确认号,ACK确认报文段
seq只要是发送报文,基本都会初始化一次,而多次发送,则会在基础上加1
若客户端发送一次,加入seq为x,那么下一次seq就为x+ 1 ( 也可以用其他字母表示,但只可以表示,实际上还是加1 )
而ack则是将接收的seq+ 1 ,来向对方确认收到,提示已经成功接收上一次所有数据
ACK报文段可以携带数据,不携带数据则不消耗序号,为1 便是确认连接
SYN= 1 ,ACK= 1 的解释
最原始的计算机通过0 和1 代表有效无效,仅仅代表这个包确认有效
SYN= 1 ,SYN包有效
ACK= 0 ,ACK包无效,ACK包不存在的意思罢了
即知道SYN只是包括了很多个东西,如seq等,而ACK也包括了很多东西而已,如ack
所以通常都会发现SYN和ACK都为1
第一次挥手: Client 将FIN置为1 ,序号seq= M ,发送给Server
进入FIN_WAIT_1 ( 套接字已关闭,正在关闭连接[ 发送FIN,没有收到ACK也没有收到FIN] ) 状态
第二次挥手: Server 收到后,将ACK置为1 ,ack= M + 1 ,响应给Client
进入CLOSE_WAIT ( 远程套接字已经关闭: 正在等待关闭这个套接字[ 被动关闭的一方收到FIN] ) 状态
Client 收到响应后
进入FIN_WAIT_2 ( 套接字已关闭,正在等待远程套接字关闭[ 在FIN_WAIT_1状态下收到发过去FIN对应的ACK] ) 状态
第三次挥手: Server 在结束所有数据传输后,将Fin 置为1 ,seq= N ,发送给Client 进入
LAST_ACK ( 远程套接字已关闭,正在等待本地套接字的关闭确认[ 被动方在CLOSE_WAIT状态下发送FIN] ) 状态
第四次挥手: Client 收到后, 将ACK置为1 ,ack= N + 1 ,响应给Server
进入TIME_WAIT ( 这个套接字已经关闭,正在等待远程套接字的关闭传送[ FIN、ACK、FIN、ACK都完毕
这是主动方的最后一个状态,在过了2 MSL时间后变为CLOSED状态] ) 状态,等待2 MSL后
进入CLOSED ( 没有使用这个套接字[ netstat 无法显示closed状态] ) 状态
Server 收到后,进入CLOSED状态
客户端和服务端通信前要进行连接,"3次握手" 的作用就是双方都能明确自己和对方的收、发能力是正常的
第一次握手: 客户端发送网络包,服务端收到了
这样服务端就能得出结论: 客户端的发送能力、服务端的接收能力是正常的
第二次握手: 服务端发包,客户端收到了
这样客户端就能得出结论: 服务端的接收、发送能力,客户端的接收、发送能力是正常的
从客户端的视角来看,我接到了服务端发送过来的响应数据包,说明服务端接收到了我在第一次握手时发送的网络包
并且成功发送了响应数据包,这就说明,服务端的接收、发送能力正常
而另一方面,我收到了服务端的响应数据包
说明我第一次发送的网络包成功到达服务端,这样,我自己的发送和接收能力也是正常的
第三次握手: 客户端发包,服务端收到了
这样服务端就能得出结论: 客户端的接收、发送能力,服务端的发送、接收能力是正常的
第一、二次握手后,服务端并不知道客户端的接收能力以及自己的发送能力是否正常
而在第三次握手时,服务端收到了客户端对第二次握手作的回应
从服务端的角度,我在第二次握手时的响应数据发送出去了,客户端接收到了
所以,我的发送能力是正常的。而客户端的接收能力也是正常的
其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力
其中FIN也是一个包也有很多东西,如seq等,为1 表示有效,0 表示无效,与SYN和ACK包一样
之所以有四次挥手而不是三次,主要是数据的完全读取,需要等待数据的操作完毕,如第二次挥手就是等待数据的操作完毕
注意:第三次握手,是可以存放某些(一般并不包括发送,如果有这样的说明,那么应该是连接成功后的,如果以后有这样的包括说明,那么就是错误的,忽略即可)信息的,即当对应确认你的接收能力可以时,将你的第三次的报文中的存放信息进行操作
否则也只有你也只能去发送信息,然后给出信息给你,当第三次没有成功
你发送信息,那么对方(服务端)就会发送失败信息,并让你操作重新连接
三次握手后,服务端一般不会在考虑响应给客户端数据了,即回到客户端请求操作,服务端响应的时间了,即客户端的主场
上面的大致说明即可,实际上对应的包只有在握手时是特殊的,否则一般需要对应(最好自己看《计算机网络》这本书)
IP地址------------------------------
192.168.1.1 - 是绝大多数路由器的登录地址,主要配置用户名和密码以及Mac过滤
IP地址是互联网中的唯一地址标识,本质上是由32位二进制组成的整数,叫做IPv4
当然也有128位二进制组成的整数,叫做IPv6,目前主流的还是IPv4
日常生活中采用点分十进制表示法来进行IP地址的描述,将每个字节的二进制转化为一个十进制整数
不同的整数之间采用小数点隔开
如:0x01020304 => 1.2.3.4
查看IP地址的方式------------------------------
Windows系统:在dos窗口中使用ipconfig或ipconfig/all命令即可
Unix/linux系统:在终端窗口中使用ifconfig或/sbin/ifconfig命令即可
特殊的地址本地回环地址(hostAddress):127.0.0.1
主机名(hostName):localhost
端口号------------------------------
IP地址 - 可以定位到具体某一台设备
端口号 - 可以定位到该设备中具体某一个进程
端口号本质上是16位二进制组成的整数,表示范围是:0 ~ 65535,其中0 ~ 1024之间的端口号通常被系统占用
建议编程从1025开始使用
特殊的端口------------------------------
HTTP:80
FTP:21
Oracle:1521
MySQL:3306
Tomcat:8080
网络编程需要提供:IP地址 + 端口号,组合在一起叫做网络套接字:Socket
基于tcp协议的编程模型------------------------------
C/S架构的简介:
在C/S模式下客户向服务器发出服务请求,服务器接收请求后提供服务
例如:在一个酒店中,顾客找服务员点菜,服务员把点菜单通知厨师,厨师按点菜单做好菜后让服务员端给客户
这就是一种C/S工作方式
如果把酒店看作一个系统,服务员就是客户端,厨师就是服务器
这种系统分工和协同工作的方式就是C/S的工作方式
客户端部分:为每个用户所专有的,负责执行前台功能
服务器部分:由多个用户共享的信息与功能,招待后台服务
编程模型------------------------------
服务器:
创建ServerSocket类型的对象并提供端口号
等待客户端的连接请求,调用accept()方法
使用输入输出流进行通信
关闭Socket
客户端:
创建Socket类型的对象并提供服务器的IP地址和端口号
使用输入输出流进行通信
关闭Socket
ServerSocket类------------------------------
public class ServerSocket
extends Object
implements Closeable
java.net.ServerSocket类主要用于描述服务器套接字信息(大插排)
常用的方法------------------------------
ServerSocket ( int port) ,根据参数指定的端口号来构造对象
Socket accept ( ) ,侦听并接收到此套接字的连接请求
void close ( ) ,用于关闭套接字
Socket类------------------------------
public class Socket
extends Object
implements Closeable
java.net.Socket类主要用于描述客户端套接字,是两台机器间通信的端点(小插排)
常用的方法------------------------------
Socket ( String host, int port) ,根据指定主机名和端口来构造对象
InputStream getInputStream ( ) ,用于获取当前套接字的输入流
OutputStream getOutputStream ( ) ,用于获取当前套接字的输出流
void close ( ) ,用于关闭套接字
注意事项------------------------------
客户端 Socket 与服务器端 Socket 对应, 都包含输入和输出流
客户端的socket.getInputStream() 连接于服务器socket.getOutputStream()
客户端的socket.getOutputStream()连接于服务器socket.getInputStream()
package com. lagou. task19 ;
import java. io. BufferedReader ;
import java. io. IOException ;
import java. io. InputStreamReader ;
import java. io. PrintStream ;
import java. net. ServerSocket ;
import java. net. Socket ;
public class ServerStringTest {
public static void main ( String [ ] args) {
ServerSocket ss = null ;
Socket s = null ;
try {
ss = new ServerSocket ( 8888 ) ;
while ( true ) {
System . out. println ( "等待客户端的连接请求..." ) ;
s = ss. accept ( ) ;
System . out. println ( "客户端" + s. getInetAddress ( ) + "连接成功!" ) ;
new ServerThread ( s) . start ( ) ;
}
} catch ( IOException e) {
e. printStackTrace ( ) ;
} finally {
if ( null != ss) {
try {
ss. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
}
}
}
package com. lagou. task19 ;
import java. io. BufferedReader ;
import java. io. IOException ;
import java. io. InputStreamReader ;
import java. io. PrintStream ;
import java. net. Socket ;
import java. util. Scanner ;
public class ClientStringTest {
public static void main ( String [ ] args) {
Socket s = null ;
PrintStream ps = null ;
Scanner sc = null ;
BufferedReader br = null ;
try {
s = new Socket ( "127.0.0.1" , 8888 ) ;
System . out. println ( "连接服务器成功!" ) ;
sc = new Scanner ( System . in) ;
ps = new PrintStream ( s. getOutputStream ( ) ) ;
br = new BufferedReader ( new InputStreamReader ( s. getInputStream ( ) ) ) ;
while ( true ) {
System . out. println ( "请输入要发送的数据内容:" ) ;
String str1 = sc. next ( ) ;
ps. println ( str1) ;
System . out. println ( "客户端发送数据内容成功!" ) ;
if ( "bye" . equalsIgnoreCase ( str1) ) {
System . out. println ( "聊天结束!" ) ;
break ;
}
String str2 = br. readLine ( ) ;
System . out. println ( "服务器回发的消息是:" + str2) ;
}
} catch ( IOException e) {
e. printStackTrace ( ) ;
} finally {
if ( null != br) {
try {
br. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
if ( null != ps) {
ps. close ( ) ;
}
if ( null != sc) {
sc. close ( ) ;
}
if ( null != s) {
try {
s. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
}
}
}
package com. lagou. task19 ;
import java. io. BufferedReader ;
import java. io. IOException ;
import java. io. InputStreamReader ;
import java. io. PrintStream ;
import java. net. InetAddress ;
import java. net. Socket ;
public class ServerThread extends Thread {
private Socket s;
public ServerThread ( Socket s) {
this . s = s;
}
@Override
public void run ( ) {
BufferedReader br = null ;
PrintStream ps = null ;
try {
br = new BufferedReader ( new InputStreamReader ( s. getInputStream ( ) ) ) ;
ps = new PrintStream ( s. getOutputStream ( ) ) ;
while ( true ) {
String s1 = br. readLine ( ) ;
InetAddress inetAddress = s. getInetAddress ( ) ;
System . out. println ( "客户端" + inetAddress + "发来的字符串内容是:" + s1) ;
if ( "bye" . equalsIgnoreCase ( s1) ) {
System . out. println ( "客户端" + inetAddress + "已下线!" ) ;
break ;
}
ps. println ( "I received!" ) ;
System . out. println ( "服务器发送数据成功!" ) ;
}
} catch ( IOException e) {
e. printStackTrace ( ) ;
} finally {
if ( null != ps) {
ps. close ( ) ;
}
if ( null != br) {
try {
br. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
if ( null != s) {
try {
s. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
}
}
}
基于udp协议的编程模型------------------------------
编程模型
接收方:
创建DatagramSocket类型的对象并提供端口号
创建DatagramPacket类型的对象并提供缓冲区
通过Socket接收数据内容存放到Packet中,调用receive方法
关闭Socket
发送方:
创建DatagramSocket类型的对象,之所以没有写端口号,是因为发送时会指定端口
创建DatagramPacket类型的对象并提供接收方的通信地址
通过Socket将Packet中的数据内容发送出去,调用send方法
关闭Socket
DatagramSocket类------------------------------
public class DatagramSocket
extends Object
implements Closeable
java.net.DatagramSocket类主要用于描述发送和接收数据报的套接字(邮局)。换句话说,该类就是包裹投递服务的发送或接收点
常用的方法------------------------------
DatagramSocket ( ) ,使用无参的方式构造对象
DatagramSocket ( int port) ,根据参数指定的端口号来构造对象
void receive ( DatagramPacket p) ,用于接收数据报存放到参数指定的位置,没有接收则会阻塞,与accept方法类似
void send ( DatagramPacket p) ,用于将参数指定的数据报发送出去
void close ( ) ,关闭Socket 并释放相关资源
DatagramPacket类------------------------------
public final class DatagramPacket
extends Object
java.net.DatagramPacket类主要用于描述数据报,数据报用来实现无连接包裹投递服务
常用的方法------------------------------
DatagramPacket ( byte [ ] buf, int length) ,根据参数指定的数组来构造对象,用于接收长度为length的数据报
如发送过来"hs" ,接收一个,则只有h,从前往后,若接收三个,则大于发送的长度,即会全部接收,并不会有其他数据
即实际上是接收两个
DatagramPacket ( byte [ ] buf, int length, InetAddress address, int port) ,根据参数指定数组来构造对象
将数据报发送到指定地址和端口,如"hse" ,发送两个,则只有hs,从前往后
上面两个都是对数组的操作,即发送的数据和接收的数组都是数组,即发送数组的数据后,将接收的数据放入数组里面
InetAddress getAddress ( ) ,用于获取发送方或接收方的通信地址
int getPort ( ) ,用于获取发送方或接收方的端口号
int getLength ( ) ,用于获取发送数据或接收数据的长度
上面所表示的地址,必须是可以找到的,如本机地址
InetAddress类------------------------------
public class InetAddress
extends Object
implements Serializable
java.net.InetAddress类主要用于描述互联网通信地址信息
常用的方法------------------------------
static InetAddress getLocalHost ( ) ,用于获取当前主机的通信地址
static InetAddress getByName ( String host) ,根据参数指定的主机名获取通信地址
package com. lagou. task19 ;
import java. io. IOException ;
import java. net. DatagramPacket ;
import java. net. DatagramSocket ;
public class ReceiveTest {
public static void main ( String [ ] args) {
DatagramSocket ds = null ;
try {
ds = new DatagramSocket ( 8888 ) ;
byte [ ] bArr = new byte [ 20 ] ;
DatagramPacket dp = new DatagramPacket ( bArr, bArr. length) ;
System . out. println ( "等待数据的到来..." ) ;
ds. receive ( dp) ;
System . out. println ( "接收到的数据内容是:" + new String ( bArr, 0 , dp. getLength ( ) ) + "!" ) ;
byte [ ] bArr2 = "I received!" . getBytes ( ) ;
DatagramPacket dp2 = new DatagramPacket ( bArr2, bArr2. length, dp. getAddress ( ) ,
dp. getPort ( ) ) ;
ds. send ( dp2) ;
System . out. println ( "回发数据成功!" ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
} finally {
if ( null != ds) {
ds. close ( ) ;
}
}
}
}
package com. lagou. task19 ;
import java. io. IOException ;
import java. net. DatagramPacket ;
import java. net. DatagramSocket ;
import java. net. InetAddress ;
public class SendTest {
public static void main ( String [ ] args) {
DatagramSocket ds = null ;
try {
ds = new DatagramSocket ( ) ;
byte [ ] bArr = "hello" . getBytes ( ) ;
DatagramPacket dp = new DatagramPacket ( bArr, bArr. length, InetAddress . getLocalHost ( ) ,
8888 ) ;
ds. send ( dp) ;
System . out. println ( "发送数据成功!" ) ;
byte [ ] bArr2 = new byte [ 20 ] ;
DatagramPacket dp2 = new DatagramPacket ( bArr2, bArr2. length) ;
ds. receive ( dp2) ;
System . out. println ( "接收到的回发消息是:" + new String ( bArr2, 0 , dp2. getLength ( ) ) ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
} finally {
if ( null != ds) {
ds. close ( ) ;
}
}
}
}
对于有些类没有close方法,是因为该类并不占有资源,如File类,只是代表路径,并不会对该文件进行操作
即会占有某些资源操作的,让其他的操作无法操作的基本上都有close方法
对于TCP和UDP,都需要端口和地址
但TCP只要accpet方法,来得到客户端,数据使用IO流传输,连接后可以直接互相传输,但必须要连接,即accpet方法要不阻塞
就如电话一样
UDP需要互相发送数据,且是具体的数据,是用数据存储,简称为缓冲区,单方面传输,若要互相传输,则又要缓冲区
只要找的到地址,就可以发送数据,而不用像TCP一样,必须要accpet不阻塞,即必须连接(中间的操作是主要的,虽然不是我们要明白的)才可,就如写信一样
虽然TCP和UDP中,地址和端口基本都知道,但是TCP有连接失败的可能性,但通过地址和端口连接成功后可以产生大量数据
只不过需要断开连接,即释放资源,而UDP虽然数据量不大,但准确,且不需要连接发送,而是直接发送
知道对方地址和端口,如电话连接(在通话时,进行连接中的过程),写信不连接(直接发送信息)
其中TCP若没有accpet方法,那么客户端就会连接失败,一般也是发送出去(前提是对应的在运行),即会确认服务端连接情况,所以TCP是通过连接的
而UDP就算没有接收的receive方法来接收,无论是否对应的运行,也会发送出去(中间有没有被拒绝那是对应端口的事了,🤭),即不会确认对方的情况,所以UDP是不同过连接的
URL类------------------------------
public final class URL
extends Object
implements Serializable
java.net.URL(Uniform Resource Identifier)类主要用于表示统一的资源定位器,也就是指向万维网上“资源”的指针
这个资源可以是简单的文件或目录,也可以是对复杂对象的引用,例如对数据库或搜索引擎的查询等
通过URL可以访问万维网上的网络资源,最常见的就是www和ftp站点,浏览器通过解析给定的URL可以在网络上查找相应的资源
URL的基本结构如下:<传输协议>://<主机名>:<端口号>/<资源地址>
常用的方法------------------------------
URL ( String spec) ,根据参数指定的字符串信息构造对象
String getProtocol ( ) ,获取协议名称
String getHost ( ) ,获取主机名称
int getPort ( ) ,获取端口号
String getPath ( ) ,获取路径信息
String getFile ( ) ,获取文件名
URLConnection openConnection ( ) ,获取URLConnection 类的实例
URLConnection类------------------------------
public abstract class URLConnection
extends Object
java.net.URLConnection类是个抽象类,该类表示应用程序和URL之间的通信链接的所有类的超类
主要实现类有支持HTTP特有功能的HttpURLConnection类
HttpURLConnection类的常用方法------------------------------
InputStream getInputStream ( ) ,获取输入流
void disconnect ( ) ,断开连接
package com. lagou. task19 ;
import java. io. BufferedReader ;
import java. io. IOException ;
import java. io. InputStream ;
import java. io. InputStreamReader ;
import java. net. HttpURLConnection ;
import java. net. MalformedURLException ;
import java. net. URL;
import java. net. URLConnection ;
public class URLTest {
public static void main ( String [ ] args) {
try {
URL url = new URL ( "https://www.lagou.com/" ) ;
System . out. println ( "获取到的协议名称是:" + url. getProtocol ( ) ) ;
System . out. println ( "获取到的主机名称是:" + url. getHost ( ) ) ;
System . out. println ( "获取到的端口号是:" + url. getPort ( ) ) ;
HttpURLConnection urlConnection = ( HttpURLConnection ) url. openConnection ( ) ;
InputStream inputStream = urlConnection. getInputStream ( ) ;
BufferedReader br = new BufferedReader ( new InputStreamReader ( inputStream) ) ;
String str = null ;
while ( ( str = br. readLine ( ) ) != null ) {
System . out. println ( str) ;
}
br. close ( ) ;
urlConnection. disconnect ( ) ;
} catch ( MalformedURLException e) {
e. printStackTrace ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
}
号是:" + url. getPort ( ) ) ;
HttpURLConnection urlConnection = ( HttpURLConnection ) url. openConnection ( ) ;
InputStream inputStream = urlConnection. getInputStream ( ) ;
BufferedReader br = new BufferedReader ( new InputStreamReader ( inputStream) ) ;
String str = null ;
while ( ( str = br. readLine ( ) ) != null ) {
System . out. println ( str) ;
}
br. close ( ) ;
urlConnection. disconnect ( ) ;
} catch ( MalformedURLException e) {
e. printStackTrace ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
}
现在我们来编写一个小型的tomcat:
因为实际上tomcat一般也是利用java来编写的,看如下代码:
package com. lagou ;
import java. io. * ;
import java. net. InetAddress ;
import java. net. ServerSocket ;
import java. net. Socket ;
public class d {
public static void main ( String [ ] args) {
try {
ServerSocket socket = new ServerSocket ( 8888 ) ;
Socket accept = socket. accept ( ) ;
System . out. println ( "有人连接我了" ) ;
InputStream inputStream = accept. getInputStream ( ) ;
BufferedReader reader = new BufferedReader ( new InputStreamReader ( inputStream) ) ;
String s = reader. readLine ( ) ;
System . out. println ( s) ;
OutputStream outputStream = accept. getOutputStream ( ) ;
PrintWriter out = new PrintWriter ( outputStream) ;
out. write ( "HTTP1.1 200 OK\r\n" ) ;
out. write ( "Content-Type:text/html;charset=UTF-8\r\n" ) ;
out. write ( "\r\n" ) ;
out. write ( "<html>" ) ;
out. write ( "<body>" ) ;
out. write ( "1" ) ;
out. write ( "</body>" ) ;
out. write ( "</html>" ) ;
out. flush ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
}
至此一个小型的tomcat编写完成,一般来说,tomcat不能访问目录,因为会当成路径,可能有特殊的情况(具体可以百度,但一般没有),当然,按照这样的说明,tomcat提供的servlet,自然最终也是操作上面的操作的,即他是网络到http的一个基础,java要与网页交互,底层基本都是这样的操作,只是大多数软件或者框架都是对他进行了很多处理而已