网络编程概述:
实现不同计算机上进行数据传输的程序。
网络编程三要素:(IP地址、端口号、协议)
IP地址找到电脑、端口号找到程序、协议传输数据
IP地址
IP地址: 指互联网协议地址(Internet Protocol Address),俗称IP。
IP地址用来给一个网络中的计算机设备做唯一的编号(相当于手机号码)。
IPV4
是一个32位的二进制数,通常被分为4个字节,表示成 a.b.c.d 的形式,例如 192.168.65.100。其中 a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个。
IPV6
由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,拟通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制 数,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
IP地址介绍
查看本机IP地址
在DOS命令行输入: ipconfig
检查网络是否连通
在DOS命令行输入: ping IP地址
特殊IP地址
127.0.0.1:是回送地址也称本地回环地址,可以代表本机的IP地址,一般用来测试使用
端口介绍
端口: 应用程序在设备中唯一的标识。
端口号: 用两个字节表示的整数,它的取值范围是0~65535。
其中0~1023之间的端口号用于一些知名的网络服务或者应用。
使用1024以上的端口号就可以了。
注意:
一个端口号只能被一个应用程序使用。
协议介绍
传输层协议:UDP、TCP
UDP协议
用户数据报协议(User Datagram Protocol)
1、不需要连接
2、速度快
3、有大小限制,一个包最多发送64K (如果大于64K,会自动拆成多个包发送)
4、易丢失数据
适用场景:
直播、语音通话、视频会话
TCP协议(重点)
传输控制协议(Transmission Control Protocol)
1、需要连接
2、速度慢
3、没有大小限制(以流的形式传输数据)
4、不易丢失数据
适用场景:
对信息安全要求较高的场景,下载、金融等数据通信
// 获取本机IP地址对象
InetAddress host = InetAddress.getLocalHost();
// 获取主机名
String hostName = host.getHostName();
// 获取IP地址字符串
String hostAddress = host.getHostAddress();
发送端 发送的是二进制数据 |
接收端 |
---|---|
1、创建发送端 2、创建一个数据包 3、发送数据包 |
1、创建接受端 2、创建空的数据包 3、接受数据 |
发送端不需要端口号,接收端需要端口号
发送端 DatagramSocket()
接收端 DatagramSocket(int post)
创建发送的数据包
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
创建接收的数据包
DatagramPacket(byte[] buf, int length)
UDP发送端
步骤:
1、创建发送端
2、创建数据包
3、发送数据
4、关流
public class UDPSender {
public static void main(String[] args) throws IOException {
// 1.创建发送端
DatagramSocket socket = new DatagramSocket();
// 2.创建数据包
byte[] bytes = "你好UDP!".getBytes();
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, InetAddress.getLocalHost(), 10011);
// 3.发送数据
socket.send(packet);
socket.close();
}
}
UDP接收端
步骤:
1、创建接收端
2、创建空的数据包
3、接收数据
4、关流
public class UDPReceiver {
public static void main(String[] args) throws IOException {
// 1.创建接收端
DatagramSocket socket = new DatagramSocket(10011);
// 2.创建空的数据包
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
// 3.接收数据
socket.receive(packet); // 没有数据会一直等待,阻塞式方法
int len = packet.getLength(); // 接收到数据的长度
System.out.println("接收到数据: " + new String(buf, 0, len));
socket.close();
}
}
注意:
1、先有接收端,然后再运行发送端
2、接收端:没有数据会一直等待,阻塞式方法
TCP协议通信需要连接,建立连接后以流的形式传输
步骤:
1、创建客户端
2、写数据
3、读数据
4、关流
public class TCPClient {
public static void main(String[] args) throws IOException {
// 1、创建客户端
Socket client = new Socket(InetAddress.getLocalHost(), 10011);
// 2、写数据
OutputStream out = client.getOutputStream();
out.write("约吗?".getBytes());
// 3、读数据
InputStream in = client.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
// 4、关流
in.close();
out.close();
client.close();
}
}
服务端
步骤:
1、创建服务端
2、接收请求
3、读数据
4、写数据
5、关流
public class TCPServer {
public static void main(String[] args) throws IOException {
System.out.println("服务端启动了");
// 创建服务端
ServerSocket server = new ServerSocket(10011);
// 接收请求
Socket socket = server.accept(); // 没有客户端连接的时候会一直停在这里
// 读数据
InputStream in = socket.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
// 写数据
OutputStream out = socket.getOutputStream();
out.write("不约?滚".getBytes());
//关流
out.close();
in.close();
socket.close();
server.close();
}
}
注意:
1、socket的流能做循环的时候无法停下来,需要在客户端调用 shutdownOutput()
2、服务端返回的socket 和客户端的socket 不同,是新建一个socket。
3、先运行服务端,再运行客户端。
4、socket.accept() 服务端没有客户端连接会一直等待,阻塞式方法。
案例1:传输文件
客户端
public class UploadClient {
public static void main(String[] args) throws IOException {
System.out.println("文件上传客户端启动啦!");
// 1.创建客户端
Socket socket = new Socket("127.0.0.1", 33445);
// 2.创建文件输入流
FileInputStream fis = new FileInputStream("D:\\MyFileTest\\xyz.png");
// 3.得到Socket的输出流
OutputStream out = socket.getOutputStream();
// 4.循环读写数据
byte[] buf = new byte[1024]; // 保存读取的数据
int len; // 保存读取的数量
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
socket.shutdownOutput(); // 告诉socket这个流没有数据啦
System.out.println("客户端发送完成!");
// 5.得到Socket输入流读取数据
InputStream in = socket.getInputStream();
len = in.read(buf); // 读取多个字节,读取到的数据保存buf中,读取的数量赋值给len
System.out.println("客户端收到: " + new String(buf, 0, len));
// 6.关闭资源
in.close();
out.close();
fis.close();
socket.close();
}
}
服务端
public class UploadServer {
public static void main(String[] args) throws IOException {
System.out.println("文件上传服务端启动啦!");
// 1.创建服务端
ServerSocket ss = new ServerSocket(33445);
// 2.同意客户端的连接
Socket socket = ss.accept();
// 3.得到Socket输入流
InputStream in = socket.getInputStream();
// 4.创建文件输出流
// UUID生成一个随机的字符串
String fileName = UUID.randomUUID().toString();
FileOutputStream fos = new FileOutputStream("study_day12\\upload\\" + fileName + ".png");
// 5.循环读写数据
byte[] buf = new byte[1024]; // 保存读取到的数据
int len; // 保存读取的数量
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
}
System.out.println("接收完毕!");
// 6.得到Socket的输出流写数据
OutputStream out = socket.getOutputStream();
out.write("上传完成!".getBytes());
// 7.关闭
out.close();
fos.close();
in.close();
socket.close();
ss.close();
}
}
1、客户端的循环读写结束了,但是服务端的循环读写没有结束 ,需要在客户端中调用 shutdownOutput()
2、原因:
客户端在读写的时候,fis在读数据,fis是文件输入流,当读取不到数据会返回-1,可以结束循环
服务端在读写数据的时候,in在读数据,in是socket的输入流,当读取不到数据,会一直等待
3、怎么解决?
客户端切断流 shutdownOutput() // 告诉客户端这个流没有数据
4、解决文件重名的问题
String fileName = UUID.randomUUID().toString()
HTTP 超文本传输协议
HTTP协议对TCP协议进行封装,需要按照HTTP规则收发数据
网站服务器的核心原理:
网站服务器是TCP服务端,发送数据给浏览器,浏览器显示
public class WebServer {
public static void main(String[] args) throws IOException {
// 网站服务器就是TCP服务端
ServerSocket ss = new ServerSocket(6688);
while (true) {
Socket socket = ss.accept();
System.out.println("有人连接啦!: " + socket);
// 给浏览器回数据
// HTTP协议对TCP协议进行了封装,我们需要按照HTTP的规则收发数据
OutputStream out = socket.getOutputStream();
out.write("HTTP/1.1 200 OK\r\n".getBytes());
out.write("Content-Type:text/html\r\n".getBytes());
out.write("\r\n".getBytes());
// 再把服务器上的web\index.html发送给浏览器
FileInputStream fis = new FileInputStream("F:\\Demo\\index.html");
byte[] buf = new byte[1024];
int len;
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
fis.close();
out.close();
socket.close();
}
}
}
在浏览器中输入: http://127.0.0.1:6688
http:// 是超文本传输协议,可以传输文字图片,视频等等资源
127.0.0.1: 服务器的IP地址
6688: 服务器的端口号
JDK1.4以前:InputStream/OutputStream称为BIO(Blocking IO) 阻塞式IO
JDK1.4推出了一套新的IO体系称为NIO (New IO/ Not Blocking IO) 非阻塞式IO
阻塞: 如果没有数据就一直等待
非阻塞: 如果没有数据,不会一直等待,可以做其他事情
非阻塞的好处,不需要一直等待,当有数据来才需要处理,没有数据可以做其他操作
BIO 两个单向的流
NIO 双向传输数据
1、Channel(通道)可以双向传输数据
2、 ByteBuffer 相当于之前BIO的byte[],可以保存要发送和接收的数据
ByteBuffer 效率比byte[]要高,功能更强大
3、Selector 选择器,可以管理多个连接
使用了多路复用,只需要一个线程就可以处理
多个通道,降低内存占用率,减少CPU切换时间,
在高并发、高频段业务环境下有非常重要的优势