视频链接:Java零基础教程
网络编程
目的:直接或间接地通过网络协议与其他计算机实现数据交换,进行通讯
两个主要问题:
- 如何准确地定位网络上一台或多台主机;定位主机上的特定的应用
- 找到主机后如何可靠高效的进行数据传输
通讯双方地址:
- IP
- 端口号
一定的规则(即:网络通讯协议。有两套参考模型)
- OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广
- TCP/IP参考模型(或TCP/IP协议):事实上的国际标准
网络通信协议:
OSI参考模型 | TCP/IP参考模型 | TCP/IP参考模型各层对应协议 |
---|---|---|
应用层 | 应用层 | HTTP、FTP、Telnet、DNS… |
表示层 | 应用层 | - |
会话层 | 应用层 | - |
传输层 | 传输层 | TCP、UDP… |
网络层 | 网络层 | IP、ICMP、ARP… |
数据链路层 | 物理层 + 数据链路层 | Link |
物理层 | 物理层 + 数据链路层 | - |
IP地址
在Java中使用InetAddress类代表IP
分类:
- IPv4:4个字节组成,4个0-255。大概434亿,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,专门为组织机构内部使用
特点:不易记忆
InetAddress inet1 = InetAdderss.getByName("192.168.10.14");
InetAddress inet2 = InetAdderss.getByName("www.antherd.com");
InetAddress inet3 = InetAddress.getLocalhost();
inet1.getHostName(); // 获取域名
inet1.getHostAddress(); // 获取ip地址
本地回路地址:127.0.0.1,对应着:localhost
端口号
端口号标识正在计算机上运行的进程(程序)
- 不同的进程有不同的端口号
- 被规定为一个16位的整数 0~65535
- 端口分类:
公认端口:0~1023。被预先定义的服务器通信占用(如:HTTP占用端口80,FTP占用端口21,Telnet占用端口23)
注册端口:1024~49151。分配给用户进程或应用程序。(如:tomcat占用端口8080,MySQL占用端口3306,Oracle占用端口1521等)
动态/私有端口:49152~65535
端口号与IP地址的组合得出一个网络套接字:Socket
网络协议
计算机网络中实现通信必须有一些约定,即通讯协议,对速率、传输代码、代码结构、传输控制、出错控制等制定标准。
问题:网络协议太复杂
计算机网络通讯涉及内容很多,比如指定源地址和目标地址,加密解密,压缩解压缩,差错控制,流量控制,路由控制,如何实现如此复杂的网络协议呢?
通讯协议分层的思想
在制定协议时,把复杂成分分解成一些简单的成分,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与下一层不发生关系。各层互不影响,利于系统的开发和拓展。
传输层协议中有两个非常重要的协议:
- 传输控制协议TCP(Transmission Control Protocol)
- 用户数据包协议UDP(User Datagram Protocol)
TCP/IP 及其两个重要协议:传输控制协议(TCP)和网络互联协议(IP)而得名,实际上是一组协议,包括多个具有不同功能且互为关联的协议。
IP(Internet Protocol)协议是网络层的主要协议,支持网间互联的数据通信。
TCP/IP 协议模型从更实用的角度出发,形成了高效的四层体系结构,即物理链路层、IP层、传输层和应用层
TCP和UDP
TCP:
- 使用TCP协议前,需先建立TCP连接,形成传输数据通道
- 传输前,采用“三次握手”方式,点对点通信,是可靠的
- TCP协议进行通信的两个应用进程:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需释放已建立的连接,效率低
客户端或服务端均可主动发起挥手动作,在socket编程中,任何一方执行close() 操作即可产生挥手操作。
UDP协议:
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64k
- 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
- 可以广播发送
- 发送数据结束时无需释放资源,开销小,速度快
TCP网络编程案例
// 客户端
@Test
public void client() {
Socket socket = null;
OutputStream os = null;
try {
// 1. 创建Socket,指明服务器端的ip和端口号
InetAddress inet = InetAddress.getByName("127.0.0.1");
socket = new Socket(inet, 8899);
// 2. 获取一个输出流,用于输出数据
os = socket.getOutputStream();
// 3. 写出数据的操作
os.write("你好,我是客户端mm".getBytes());
socket.shutdownOutput(); // 关闭数据的输出
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4. 资源的关闭
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 服务端
@Test
public void server() {
Socket socket = null;
InputStream is = null;
try {
// 1. 创建服务器的ServerSocket,指明自己的端口号
ServerSocket ss = new ServerSocket(8899);
// 2. 调用accept() 表示接受来自客户端的socket
socket = ss.accept();
// 3. 获取输入流
is = socket.getInputStream();
// 4. 读取输入流中的数据
byte[] buffer = new byte[1024]; // 可能产生乱码
int len;
while((len = is.read(buffer)) != -1) {
String str = new String(buffer, 0, len);
System.out.print(str);
}
System.out.println("收到来自于:" + socket.getInetAddress().getHostAddress());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 5. 关闭资源
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
先启动服务端,然后启动客户端。
UDP网络编程案例
// 发送端
@Test
public void send() throws IOException {
DatagramSocket socket = new DatagramSocket();
String str = "我是UDP方式发送的消息";
byte[] data = str.getBytes();
InetAddress inet = InetAddress.getLocalHost();
DatagramPacket packet = new DatagramPacket(data, 0, data.length, inet, 9000);
socket.send(packet);
socket.close();
}
// 接收端
@Test
public void receiver() throws IOException {
DatagramSocket socket = new DatagramSocket(9000);
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()));
socket.close();
}
URL编程
- URL(Uniform Resource Locator):统一资源定位符,它表示Internet上某一资源的地址
- 它是一种具体的URI,即URL可以用来表示一个资源,而且还指明了如何locate这个资源
- 通过URL,我们可以访问Internet上的各种网络资源,比如最常见的www,ftp站点。浏览器通过解析给定的URL可以在网络上查找响应的文件或其他资源
- URL的基本结构由5部分组成:
<传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表
例如:http://192.168.1.100:8080/helloworld/index.jsp#a?username=shkstart&password=123
#片段名:即锚点,例如看小说,直接定位到章节
参数列表格式:参数名=参数值&参数名=参数值…
HttpURLConnection urlConnection = null;
InputStream is = null;
FileOutputStream fos = null;
try {
URL url = new URL("http://localhost:8080/examples/beauty.jpg?username=Tom");
System.out.println(url.getProtocol());
System.out.println(url.getHost());
System.out.println(url.getPort());
System.out.println(url.getPath());
System.out.println(url.getFile());
System.out.println(url.getQuery());
// 下载资源
urlConnection = (HttpURLConnection) url.openConnection();
is = urlConnection.getInputStream();
fos = new FileOutputStream(new File("beauty2.jpg"));
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
} 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();
}
}