一、网络编程基础知识
1、什么是网络编程
在网络环境上使用IO流进行数据传输
2、Java提供了什么
网络编程相关定义和实现,联网的底层细节被隐藏在 Java 的JVM。
程序员面对的是一个统一的网络编程环境。这也被称为:IO编程
二、如何在Java平台上完成网络通信
1、网络通信协议:
TCP/IP模型 对应协议
应用层 HTTP、ftp、telnet、DNS…
传输层 TCP、UDP、…
网络层 IP、ICMP、ARP…
物理+数据链路层 Link
2、数据在网络中是如何传输的:
数据封装(从上至下) / 数据拆封(从下至上)
传输层 Segment
网络层 Packet
数据链路层 Frame
物理层 Bits
3、核心两点
确定通信双方的地址
1 )如何确定?两种方式:
> IP 地址: 192.168.10.165
//唯一的标识 Internet 上的计算机
> 域名: [www.atguigu.com](http://www.atguigu.com/)
//域名服务器(DNS)负责将域名转化成IP地址,即可与主机建立连接
2)java编写要使用的类
[java.net](http://java.net/).InetAddress 类 : 表示 IP 地址
①两个子类:Inet4Address、Inet6Address。
②InetAddress 类的一个对象就代表着一个IP地址
3) 常用方法:
①InetAddress类没有提供公共的构造器,提供两个静态方法来获取InetAddress实例
>getByName(String host) : 根据域名/IP地址获取对应的 InetAddress 实例
②getHostName() : 获取IP地址对应的域名
③getHostAddress() : 获取IP地址
④getLocalHost() : 获取 本机 的 IP
4)端口号:
不同的程序有固定的端口号。发送和接收都需对应上。
满足:网络通信协议(TCP、UDP)
TCP协议:
使用TCP协议前,须先建立TCP连接,形成传输数据通道
传输前,采用“三次握手”方式,是可靠的
TCP协议进行通信的两个应用进程:客户端、服务端
在连接中可进行大数据量的传输
传输完毕,需释放已建立的连接,效率低
UDP协议:
将数据、源、目的封装成数据包,不需要建立连接
每个数据报的大小限制在64K内
因无需连接,故是不可靠的
发送数据结束时无需释放资源,速度快l
4、URL (统一资源定位符)
1、定义:代表网上某站点的某一资源
2、URL的基本结构由5部分组成:
<传输协议>://<主机名>:<端口号>/<文件名>
例如: [http://www.atguigu.com:9999/helloworld/index.jsp](http://www.atguigu.com:9999/helloworld/index.jsp)
注:<主机名>都使用域名代替了
3、常用方法
public String getProtocol( ) 获取该URL的协议名
public String getHost( ) 获取该URL的主机名
public String getPort( ) 获取该URL的端口号
public String getPath( ) 获取该URL的文件路径
public String getFile( ) 获取该URL的文件名
public String getRef( ) 获取该URL在文件中的相对位置
public String getQuery( ) 获取该URL的查询名
【注意】:站点上的下载链接其实就是URL,有加密与未加密的。
三、使用 TCP 协议完成网络通信
简化场景:客户端每隔两秒发送一个带有时间戳的"hello world"给服务端,服务端收到之后打印。
服务端(先开):ServerSocket
步骤
1 传入端口号,创建一个ServerSocket的对象
2 阻塞接收Socket = 获取与客户端连接并返回
3 获取从客户端Socket对象发送过来的输入流
4 操作过程
5 关闭相应的流和 Socket、ServerSocket对象
package com.dodou.liwh.ws.socket;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
-
@author: Lwh
-
@ClassName: IOServer
-
@Description:
-
@version: 1.0.0
-
@date: 2019-03-25 3:49 PM
*/
public class IOServer {
public static void main(String[] args) throws Exception {
//构建服务端对象
ServerSocket serverSocket = new ServerSocket(8080);
new Thread(() -> {
while (true) {
try {
//阻塞获取客户端连接,获取到一个连接就创建一个新的线程
Socket socket = serverSocket.accept();
new Thread(() -> {
try {
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
// 按字节流方式读取数据到bytes再转换为String输出
while ((len = inputStream.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
客户端:Socket
(称为“套接字”,一个 IP地址与 端口号 的组合)
步骤
1 重载构造器,传入端口号,Ip 创建一个Socket的对象
2 获取输出流,写出数据
3 操作过程
4 关闭相应的流和 Socket
package com.dodou.liwh.ws.socket;
import java.net.Socket;
import java.util.Date;
/**
-
@author: Lwh
-
@ClassName: IOClient
-
@Description:
-
@version: 1.0.0
-
@date: 2019-03-25 4:15 PM
*/
public class IOClient {
public static void main(String[] args) {
new Thread(() -> {
//获取一个Socket的对象
try {
Socket socket = new Socket("127.0.0.1", 8000);
while (true) {
try {
//获取输出流,写出数据
socket.getOutputStream().write((new Date() + ": hello world").getBytes());
socket.getOutputStream().flush();
Thread.sleep(2000);
} catch (Exception e) {
}
}
} catch (Exception e) {
}
}).start();
}
}
image.png四、缺点
上面的demo,从服务端代码中我们可以看到,在传统的IO模型中,每个新的客户端连接成功之后
服务端都需要一个线程来维护这条连接,每个线程包含一个while死循环
那么1w个连接对应1w个线程,继而1w个while死循环,这就带来如下几个问题:
-
线程资源受限:线程是操作系统中非常宝贵的资源,同一时刻有大量的线程处于阻塞状态是非常严重的资源浪费,操作系统耗不起
-
线程切换效率低下:单机cpu核数固定,线程爆炸之后操作系统频繁进行线程切换,应用性能急剧下降。
-
除了以上两个问题,IO编程中,我们看到数据读写是以字节流为单位,效率不高。
为了解决这三个问题,JDK在1.4之后提出了NIO。
网友评论