网络基础
计算机网络
- 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、 共享硬件、软件、数据信息等资源
网络编程的目的
- 直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯
网络编程中有两个主要的问题
- 如何准确地定位网络上一台或多台主机;定位主机上的特定的应用
- 找到主机后如何可靠高效地进行数据传输
网络通信要素
- IP和端口号
- 网络通信协议
如何实现网络中的主机互相通信
通信双方地址
- IP
- 端口号
一定的规则(网络通信协议,有两套参考模型)
- OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广
- TCP/IP参考模型(或TCP/IP协议):事实上的国际标准
网络通信协议
Java中获取网络通信的信息
InetAddress类没有提供公共的构造器,而是提供了如下几个静态方法来获取 InetAddress实例
public static InetAddress getLocalHost()
public static InetAddress getByName(String host)
InetAddress提供了如下几个常用的方法
public String getHostAddress()
:返回 IP 地址字符串(以文本表现形式)public String getHostName()
:获取此 IP 地址的主机名public boolean isReachable(int timeout)
:测试是否可以达到该地址
代码示例:
package com.atguigu.java1;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressTest {
public static void main(String[] args) {
try {
InetAddress inet1 = InetAddress.getByName("www.baidu.com");
System.out.println(inet1);
//获取本地ip
InetAddress inet2 = InetAddress.getLocalHost();
System.out.println(inet2);
//getHostName()
System.out.println(inet2.getHostName());
//getHostAddress()
System.out.println(inet2.getHostAddress());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
网络编程
TCP 和 UDP的区别
TCP
- 使用TCP协议前,须先建立TCP连接,形成传输数据通道
- 传输前,采用“三次握手”方式,点对点通信,是可靠的
- TCP协议进行通信的两个应用进程:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需释放已建立的连接,效率低
UDP
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64K内
- 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
- 可以广播发送
- 发送数据结束时无需释放资源,开销小,速度快
Socket
- 利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实 上的标准
- 通信的两端都要有Socket,是两台机器间通信的端点,网络通信其实就是Socket间的通信
- Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输
- 一般主动发起通信的应用程序属客户端,等待通信请求的为服务端
Socket的分类
- 流套接字(stream socket):使用TCP提供可依赖的字节流服务
- 数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务
客户端创建Socket对象
客户端程序可以使用Socket类创建对象,创建的同时会自动向服务器方发起连接
服务器建立 ServerSocket 对象
ServerSocket 对象负责等待客户端请求建立套接字连接,类似邮局某个窗口 中的业务员。也就是说,服务器必须事先建立一个等待客户请求建立套接字 连接的ServerSocket对象
所谓“接收”客户的套接字请求,就是accept()方法会返回一个 Socket 对象
详细请看下面的代码示例
TCP网络编程
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 实现TCP的网络编程
* 例子1:客户端发送信息给服务端,服务端将数据显示在控制台上
*
*/
public class TCPTest1 {
//客户端
@Test
public void client() {
Socket socket = null;
OutputStream os = null;
FileInputStream fis = null;
ByteArrayOutputStream baos = null;
nputStream is = null;
try {
//1.创建Socket对象,指明服务器端的ip和端口号
socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
//2.获取一个输出流,用于输出数据
os = socket.getOutputStream();
//3.将图片读取入程序中
fis = new FileInputStream(new File("spring.jpg"));
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
os.write(buffer,0,len);
}
//4.关闭数据的输出
socket.shutdownOutput();
//5.接收来自于服务器端的数据,并显示到控制台上
is = socket.getInputStream();
baos = new ByteArrayOutputStream();
byte[] bufferr = new byte[20];
int len1;
while((len1 = is.read(buffer)) != -1){
baos.write(buffer,0,len1);
}
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源的关闭
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(baos != null){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os != null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//服务端
@Test
public void server() {
ServerSocket ss = null;
Socket socket = null;
InputStream is = null;
FileOutputStream fos = null;
OutputStream os = null;
try {
//1.创建服务器端的ServerSocket,指明自己的端口号
ss = new ServerSocket(9090);
//2.调用accept()表示接收来自于客户端的socket
socket = ss.accept();
//3.获取输入流
is = socket.getInputStream();
//4.获得输出流
fos = new FileOutputStream(new File("spring-server.jpg"));
//5.读取输入流中的数据
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
//6.服务器端给予客户端反馈
os = socket.getOutputStream();
os.write("你好,已收到图片,".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(os != null){
//7.关闭资源
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos != null){
//7.关闭资源
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(ss != null){
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
UDP网络编程
- 类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序
- UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证 UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达
- DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP 地址和端口号以及接收端的IP地址和端口号
- UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和 接收方的连接。如同发快递包裹一样
DatagramSocket 类的常用方法
代码示例
package com.atguigu.java1;
import org.junit.Test;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* UDP协议的网络编程
*/
public class UDPTest {
//发送端
@Test
public void sender(){
DatagramSocket socket = null;
try{
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);
}catch(IOException e){
e.printStackTrace();
}finally{
if(socket != null){
socket.close();
}
}
}
//接收端
@Test
public void receiver(){
DatagramSocket socket = null;
try{
byte[] buffer = new byte[100];
DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
socket.receive(packet);
System.out.println(new String(packet.getData(),0,packet.getLength()));
}catch(IOException e){
e.printStackTrace();
}finally{
if(socket != null){
socket.close();
}
}
}
}
URL网络编程
URL(Uniform Resource Locator)
- 统一资源定位符,它表示 Internet 上某一 资源的地址
- 它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源
- 通过 URL 我们可以访问 Internet 上的各种网络资源,比如最常见的 www,ftp 站点。浏览器通过解析给定的 URL 可以在网络上查找相应的文件或其他资源
URL的基本结构由5部分组成
- <传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表
例如:
URL类
为了表示URL,java.net 中实现了类 URL。
构造方法:
public URL (String spec)
:通过一个表示URL地址的字符串可以构造一个URL对象
URL url = new URL ("http://www. ********.com/");
public URL(URL context, String spec)
:通过基 URL 和相对 URL 构造一个 URL 对象
URL downloadUrl = new URL("http://www. ********.com/", “download.html")
public URL(String protocol, String host, String file)
:通过协议、基 URL 和相对 URL 构造一个 URL 对象
URL downloadUrl = new URL("http", "http://www. ********.com/", “download. html");
public URL(String protocol, String host, int port, String file)
:通过协议、基 URL 、端口号和相对 URL 构造一个 URL 对象
URL gamelan = new URL("http", "http://www. ********.com/", 80, “download.html");
常用方法有:
public String getProtocol( )
:获取该URL的协议名public String getHost( )
:获取该URL的主机名public String getPort( )
:获取该URL的端口号public String getPath( )
:获取该URL的文件路径public String getFile( )
:获取该URL的文件名public String getQuery( )
:获取该URL的查询名
URLConnection类
URLConnection类是针对HTTP协议的,URL的方法 openStream()
能从网络上读取数据,若希望输出数据,例如向服务器端的 CGI (公共网关接口-Common Gateway Interface-的简称,是用户浏览器和服务器端的应用程序进行连接的接口)程序发送一 些数据,则必须先与URL建立连接,然后才能对其进行读写,此时需要使用
openConnection()
:当与一个URL建立连接时, 首先要在一个 URL 对象上通过方法 openConnection() 生成对应的 URLConnection 对象。如果连接过程失败,将产生IOException
URL netchinaren = new URL ("http://localhost:8080/photo/spring.jpg");
URLConnectonn u = netchinaren.openConnection( );
通过URLConnection对象获取的输入流和输出流
public InputStream getInputStream( )throws IOException
public OutputSteram getOutputStream( )throws IOException
实现从Tomcat下载图片
package com.atguigu.java1;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class URLTest1 {
public static void main(String[] args) {
HttpURLConnection urlConnection = null;
InputStream is = null;
FileOutputStream fos = null;
try {
URL url = new URL("http://localhost:8080/photo/spring.jpg");
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
is = urlConnection.getInputStream();
fos = new FileOutputStream("spring.jpg");
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
System.out.println("下载完成");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(urlConnection != null){
urlConnection.disconnect();
}
}
}
}