网络编程
概述
Java是Internet上的语言,它从语言级上提供了对网络应用程序的支持,程序员能很容易开发常见的网络应用程序
Java提供的网络类库,可以实现无痛的网络链接,联网的底层细节被隐藏在Java的本机安装系统里,由JVM进行控制。并且Java实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。
计算机网络:把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、共享硬件、软件、数据信息等资源
网络编程的目的:直接或间接地通过网络协议与其他计算机实现数据交换,进行通讯
网络编程中地两个主要问题:如何准确地定位网络上一台或多态主机;定位主机上地特定地应用。找到主机后如何可靠高效地进行数据传输。
通信双方的地址:
ip
端口号
一定的规则(即:网络通信协议。有两条参考模型)
OSI参考模型:模型过于理想化,未能在因特网上进行广泛应用
TCP/IP参考模型(或TCP/IP协议):事实上的国际标准
计算机网络分层模型 | ||
---|---|---|
OSI七层模型 | TCP/IP四层模型 | TCP/IP参考模型 |
应用层 | 应用层 | HTTP、FTP、Telnet、DNS... |
表示层 | ||
会话层 | ||
传输层 | 传输层 | TCP、UDP、... |
网络层 | 网络层 | IP、ICMP、ARP |
数据链路层 | 物理+数据链路层 | Link |
物理层 |
通信要素1:IP和端口号
IP
IP地址:InetAddress
唯一标识Internet上的计算机(通信实体)
本地回环地址(hostAddress):127.0.0.1 主机名(hostname):localhost
IP地址分类方式1:IPV4和IPV6
- IPV4:4个字节组成,4个0-255,大概42亿,30亿都在北美,亚洲4亿,2011年初已经用尽。以点分十进制标识,如192.168.0.1
- IPV6:128位(16个字节),写成8个无符号证书,每个整数用四个十进制为标识,数之间用冒号(:)分开,如
3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
- IP地址分类方式2:公网地址(万维网使用)和私有地址(局域网使用),192.168.开头的就是私有地址,范围几位192.168.0.0-192.168.255.255,专门为组织机构内部使用
- 域名:www.baidu.com等
- 本机回路地址:127.0.0.1 代表本机 对应着localhost
- 如何实例化InetAddress:两个方法:getByName(String host)、getLocalHost();两个常用方法:getHostName()/getHostAddress()
特点:不易记忆。
public static void main(String[] args){
try{
//类似File
InetAddress inet1 = InetAddress.getByName("192.168.10.14");
System.out.println(inet1);
InetAddress inet2 = InetAddress.getByName("www.baidu.com");
System.out.println(inet2);
//获取本机
InetAddress inet4 = InetAddress.getLocalHost();
System.out.println(inet4);
}catch(UnkonwHostException e){
e.printStackTrace();
}
}
端口号
端口号表示正在计算机上运行的进程(程序)
- 不同的进程有不同的端口号
- 并规定为一个16位的整数 0-65535
- 端口分类:
公认端口:0-1023。呗预先定义的服务通信占用(如:HTTP占用端口号80,FTP占用端口21,Telnet占用端口23
注册端口:1024-49151。分配给用户进程或应用程序(如:Tomcat占用端口8080,Mysql占用端口3306,oracle占用端口1521等)
动态/私有端口:491452~65535
端口号与IP地址的组合可以得出一个网络套接字:Socket
网络通信要素二:网络协议
- 网络通信协议
计算机网络中实现通信必须有一些约定,即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等指定标准。 - 问题:网络协议太复杂
计算机网络通信涉及内容很多,比如指定源地址和目标地址,加密解密,压缩,解压缩,差错控制,流量控制,路由控制,如何实现如此复杂的网络协议呢? - 通信协议分层的思想
在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展。
TCP/IP协议簇
传输层协议有两个非常重要的协议:
- 传输控制协议TCP(Transmission Control Protocol)
- 用户数据报协议UDP(User Datagram Protocol)
TCP/IP以及两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得名,实际上是一组协议,包括多个具有不同功能且互为关联的协议
IP(Internet Protocol)协议是网络层的主要协议,支持网间互联的数据通信。
TCP/IP协议模型从更实用的角度出发,形成了高效的四层体系结构,即物理链路层、IP层、传输层和应用层。
TCP和UDP
TCP协议:
使用TCP协议前,须先建立TCP连接,形成传输数据通道
传输前,采用“三次握手”方式,点对点通信,是可靠的
TCP协议进行通信的两个应用进程:客户端、服务端
在连接中可进行大数据量的传输
传输完毕,需释放已建立的连接,效率低
UDP协议:
将数据、源、目的封装成数据包,不需要建立连接
每个数据报的大小限制在64K内
发送不管对方是否准备好吗,接收方收到也不确认,故是不可靠的
可以广播发送
发送数据结束无需释放资源,开销小,速度快
实现TCP的网络编程
//例子1:客户端发送信息给服务端,服务端将数据显示在控制台上
//客户端
@Test
public void client()throws IOException{
InetAddress inet = InetAddress.getByName("127.0.0.1");
Socket socket = new Socket(inet,8899);
OutputStream os = socket.getOutputStream();
os.write("你好,我是客户端".getBytes);
os.close();
socket.close();
}
//服务端
@Test
public void server(){
ServerSocket ss = new ServerSocket(8899);
Socket socket = ss.accept();
//InputStream is = socket.getInputStream();
//不建议这样写,可能会有乱码
//byte[] bufer = new byte[20];
//int len;
//while((len=is.read(buffer)!=-1){
//String str = new String(buffer,0,len);
//System.out.print(str);
//}
ByteArrayOutputStrem baos = new ByteArrayOutputStream();
byte[] buffer = new byte[5];
int len;
while((len=is.read(buiffer))!=-1){
baos.write(buffer,0,len);
}
System.out.println(baos.toString());
System.out.println("收到了来自于:"+socket.getInetAddress().getHostAddress()+"的数据")
//关闭资源
baos.close();
is.close();
socket.close();
ss.close();
}
//例题二:客户端发送文件给服务端,服务端将文件保存在本地
@Test
public void client(){
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
OutputStream os = socket.getOutputStream();
FileInputStream fis = new FileInputStream(new File("beauty.jpg"));
byte[] bufer = new byte[1024];
int len;
while((len=fis.read(buffer)!=-1){
os.write(buffer,0,len);
}
fis.close();
os.close();
socket.close();
}
@Test
public void server(){
ServerSocket ss = new ServerSocket("9090");
Socket socket = ss.accept();
InputStream is = socket.getInputStream;
FileOutputStream fos = new FileOutputStream(new File("beauti1.jpg"));
byte[] buffer = new byte[1024];
int len;
while((len=fos.read(buffer)!=-1){
fos.write(buffer,0,len);
}
fos.close();
is.close();
socket.close();
ss.close();
}
//例题3:从客户端发送文件给服务端,服务端保存到本地,并返回"发送成功“给客户端,并关闭相应的连接
@Test
public void client()throws IOExcetpion{
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
OubputStream os = socket.getOutputStream();
FileInputStream fis = new FileInputStream(new File("beauty.jpg" ));
byte[] buffer = new byte[10240];
int len;
while((len=fis.read(bufer))!=-1){
os.write(buffer,0,len);
}
//接受来自于服务器端的数据,并显示到控制台上
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[20];
int len1;
while((le1n = is.read(bufer))!=-1){
baos.write(buffer,0,len1);
}
//关闭数据的输出
socket.shutdown();
System.out.println(baos.toString());
baos.close();
is.close();
fis.close();
os.close();
socket.close();
}
@Test
public void server()throws IOException{
ServerSocket ss = new ServerSocket(9090);
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream(new File("beauty1.jpg"));
byte[] buffer = new byte[1024];
int len;
while((len=is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
//服务器给予客户端反馈
OutputStream os = socket.getOutputStream();
os.write("你好!照片已经收到!");
os.close();
fos.close();
is.close();
socket.close();
ss.close();
}
客户端+服务端
客户端:自定义,浏览器
服务端:自定义,Tomcat服务器
UDP网络编程
类DatagramSocket和DatagramPacket实现了基于UDP协议的网络程序。
UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
DatagramPacket对象封装了UDP数据报,在数据报中国你包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
UDP协议中每个数据报都给出了完整的地址信息,因此无须简历发送方和接收方的连接,如同发快递包裹一样
//UDP协议的网络编程
//发送端
@Test
public void sender()throws SocketException(){
DatagramSocket socket = new DatagramSocket();
String str = "我是UDP方式发送的导弹";
byte[] data = str.getBytes();
InetAddress inet = InetAddress.getLocalHost();
DatagramPacket packet = new DatagramPacket(data,0,data.length,inet,9090);
socket.send(packet);
socket.close();
}
//接收端
@Test
public void receiver(){
DatagramSocket socket = new DatagramSocket(9090);
byte[] bufer = new byte[100];
DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
socket.receive(packet);
System.out.println(new String(packet.getData(),packet.getLength()));
socket.close();
}
URL编程
URL(Uniform Resource Locator)
:统一资源定位符,它表示Internet上某一资源的地址
它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源
通过URL我们可以访问Internet上的各种网络资源,比如最常见的www,ftp站点。浏览器通过解析给定的URL可以在网络上查找对应的文件或其他资源。
URL的基本结构由5部分组成:
<传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表
例如:http://192.168.1.100:8080/helloword/index.jsp#username=shkstart&password=123
#片段名
:即锚点,例如看小说,直接定位到章节
参数列表格式:参数名=参数值&参数名=参数值...
为了标识URL,java.net中实现了类URL。我们可以通过下面的构造器来初始化一个URL对象:
public URL(String spec):通过一个URL地址的字符串可以构造一个URL对象。
public URL(URL context,String spec):通过基URL和相对URL构造一个URL对象
public URL(String protocol,String host,String file);
public URL(String protocol,String host,int port,String file);
//一个URL对象生成后,其属性是不能呗改变的,但可以通过它给定的方法来获取这些属性
public String getProtocol():获取该URL的协议名
public String getHost():获取该URL的主机名
public String getPort():获取该URL的端口号
public String getPath():获取该URL的文件路径
public String getFile():获取该URL的文件名
public String getQuery():获取该URL的查询名
//URL网络编程
public static void main(String[] args){
try{
URL url = new URL("http://localhost:8080/examples/beauty.jpg);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.connect();
InputStream is = urlConnection.getInputStream();
FileOutputStream fos = new FileOutputStream("beauty3.jpg");
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
is.close();
fos.close();
urlConnection.disconnect();
}catch(Exception e){
e.printStackTrace();
}
}