人生不是坐等暴风雨过去,而是学会在雨中起舞
—— 24.6.14
一、网络编程的基础概念
1.概述:
在网络通信协议下,不同计算机上运行的程序,进行数据传输
比如:通信、视频通话、网络、邮件
只要是计算机之间通过网络进行数据传输,就有网络编程的存在
2.软件结构
C/S结构
Client/Server结构(需要安装客户端),指客户端和服务器结构,常见程序有QQ、红蜘蛛等软件
好处:不用把数据全部存放在服务端,一些数据存放在客户端 坏处:不易维护,需要开发客户端和服务端两个程序
B/S结构
Browser/Server结构,指浏览器和服务端结构,常见浏览器有IE、谷歌、火狐等
好处:便于迭代,不用单独维护客户端,因为维护服务器会自动同步到客户端
坏处:所有的数据都在服务端,会造成服务器的压力
两种架构各有优势,但是无论哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,实现两台计算机的通信的程序。
3.服务器概念
1.概述:安装了服务器软件的计算机
2.最开始学习的服务器软件:tomcat
网络通信协议:两台计算机在做数据交互时要遵守的规则,协议会对数据的格式,速率等进行规定,只有都遵守了这个协议,才能完成数据交互,两台计算机想完成数据交互,需要遵守网络通信协议
4.通信三要素
[IP地址]:
计算机的唯一标识,用于两台计算机之间的连接
a.概述:指互联网协议地址(Internet Protocol Address),俗称IP计算机的唯一标识
b.作用:可用于计算机和计算机之间的连接
c.IPV4
32位的二进制数,通常被分为4个字节,表示成a.b.c.d 的形式,例如192.168.65.100 。其中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个。
IPV6
为了扩大地址空间,拟通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,表示成ABCD:EFO1:2345:6789:ABCD:EF01:2345:6789
d.查看ip的命令:ipconfig
测试是否能连接其他计算机的命令:ping ip地址
e:特殊的网址:代表的是本机地址,到了哪里都不会变,代表自己127.0.0.1 —> 固定不变
localhost
[协议]:
TCP:面向连接协议
需要先确认连接,才能进行数据交互
三次握手:(连接之前的反复确认)
① 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
② 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
③ 第三次握手,客户端再次向服务器端发送确认信息,确认连接。
好处:数据安全,能给数据的传输提供一个安全的传输坏境
坏处:效率低
UDP:面向无连接协议
好处:效率高
坏处:传输的数据不安全,容易丢失数据包
[端口号]
每一个应用程序的唯一标识
用两个字节表示的整数,它的取值范围是0~65535。其中,0~1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
5.TCP协议中的三次握手和四次挥手
三次握手:
第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
第三次握手,客户端再次向服务器端发送确认信息,确认连接。
四次挥手:
第一次挥手:客户端向服务器端提出结束连接,让服务器做最后的准备工作。此时,客户端处于半关闭状态,即表示不再向服务器发送数据了,但是还可以接受数据
第二次挥手:服务器接收到客户端释放连接的请求后,会将最后的数据发给客户端。并告知上层的应用进程不再接收数据。
第三次挥手:服务器发送完数据后,会给客户端发送一个释放连接的报文。那么客户端接收后就知道可以正式释放连接了。
第四次挥手:客户端接收到服务器最后的释放连接报文后,要回复一个彻底断开的报文。这样服务器收到后才会彻底释放连接。这里客户端,发送完最后的报文后,会等待2MSL,因为有可能服务器没有收到最后的报文,那么服务器迟迟没收到,就会再次给客户端发送释放连接的报文,此时客户端在等待时间范围内接收到,会重新发送最后的报文,并重新计时。如果等待2MSL后,没有收到,那么彻底断开。
二、UDP协议编程
1.DatagramSocket —> 好比寄快递找的快递公司
2.DatagramPacket —> 好比快递公司打包
1.客户端(发送端)
1.创建Datagramsocket对象(快递公司)
a.空参:端口号从可用的端口号中随机一个使用
b.有参:自己指定
2.创建DatagramPacket对象,将数据进行打包
a.要发送的数据 —> byte[]
b.指定接收端的IP
c.指定接收端的端口号
3.发送数据
4.释放资源
package S102Internet;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Demo287UDP_Sent {
public static void main(String[] args) throws Exception {
// 1.创建Datagramsocket对象(快递公司)
// a.空参:端口号从可用的端口号中随机一个使用
// b.有参:自己指定
DatagramSocket Socket = new DatagramSocket();
// 2.创建DatagramPacket对象,将数据进行打包
// a.要发送的数据 —> byte[]
// b.指定接收端的IP
// c.指定接收端的端口号
byte[] buf = "我一直相信".getBytes();
InetAddress IP = InetAddress.getByName("127.0.0.1");
int port = 6666;
DatagramPacket dp = new DatagramPacket(buf, buf.length, IP, port);
// 3.发送数据
Socket.send(dp);
// 4.释放资源
Socket.close();
}
}
直接执行发现,发送端在没有接收端的情况下,不会报错,因为UDP协议是面向无连接协议,不管有没有接收端,照发不误
2.服务端(接收端)
1.创建DatagramSocket对象,指定服务端的端口号
2.接收数据包
3.解析数据包
4.释放资源
package S102Internet;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Demo288UDP_Receive {
public static void main(String[] args) throws Exception {
// 1.创建DatagramSocket对象,指定服务端的端口号
DatagramSocket socket = new DatagramSocket(6666);
// 2.接收数据包
byte[] bytes = new byte[1024]; // 用于保存接收过来的数据
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
socket.receive(dp);
// 3.解析数据包
byte[] data = dp.getData(); // 接收的资源
int len = dp.getLength(); // 从数据包中获取多少数据
InetAddress address = dp.getAddress(); // 获取发送端的主机
int port = dp.getPort(); // 发送端的端口号
System.out.println(new String(data, 0, len));
System.out.println(address+"……"+port);
// 4.释放资源
socket.close();
}
}
三、TCP协议编程
1.客户端和服务端的交互过程
2.编写客户端
1.创建socket对象,指明服务端的ip以及端口号
2.调用socket中的getoutputstream,往服务端发送请求
3.调用socket中的getInputstream,读取服务端响应回来的数据
4.关流
package S102Internet;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Demo289TCP_Client {
public static void main(String[] args) throws Exception {
// 1.创建socket对象,指明服务端的ip以及端口号
Socket socket = new Socket("127.0.0.1", 6666);
// 2.调用socket中的getOutputStream,往服务端发送请求
OutputStream os = socket.getOutputStream();
os.write("一切都会好的".getBytes());
// 3.调用socket中的getInputStream,读取服务端响应回来的数据
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes, 0, len));
// 4.关流
is.close();
os.close();
socket.close();
}
}
3.编写服务端
1.创建Serversocket对象,设置端口号
2.调用Serversocket中的accept方法,等待客户端连接,返同Socket对象
3.调用socket中的getInputStream,用于读取客户端发送过来的数据
4.调用socket中的getOutputStream,用于给客户响应数据
5.关闭资源
package S102Internet;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Demo289TCP_Client {
public static void main(String[] args) throws Exception {
// 1.创建socket对象,指明服务端的ip以及端口号
Socket socket = new Socket("127.0.0.1", 6666);
// 2.调用socket中的getOutputStream,往服务端发送请求
OutputStream os = socket.getOutputStream();
os.write("一切都会好的".getBytes());
// 3.调用socket中的getInputStream,读取服务端响应回来的数据
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes, 0, len));
// 4.关流
is.close();
os.close();
socket.close();
}
}
package S102Internet;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Demo290TCP_Server {
public static void main(String[] args) throws Exception {
// 1.创建Serversocket对象,设置端口号
ServerSocket ss = new ServerSocket(6666);
// 2.调用Serversocket中的accept方法,等待客户端连接,返同Socket对象
Socket socket = ss.accept();
// 3.调用socket中的getInputstream,用于读取客户端发送过来的数据
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes, 0, len));
// 4.调用socket中的getoutputstream,用于给客户响应数据
OutputStream os = socket.getOutputStream();
os.write("我一直相信".getBytes());
// 5.关闭资源
is.close();
os.close();
socket.close();
ss.close();
}
}
四、文件上传
经过一个客户端、一个服务端,将一个文件上传到另一个设备上面,用普通IO流操作硬盘上的文件
1.文件上传客户端以及服务端实现
客户端
package S103InternetFileUpload;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Demo291Client {
public static void main(String[] args) throws Exception {
// 1.创建Socket对象
Socket socket = new Socket("127.0.0.1",6666);
// 2.创建FileInputStream,用于读取本地上的图片
FileInputStream fis = new FileInputStream("D:\\2LFE\\Desktop\\前端三剑客\\css\\CSS.day4\\综合案例-抖音解决方案.jpg");
// 3.调用getOutputStream,用于将读取过来的图片写给服务端
OutputStream os = socket.getOutputStream();
// 4.边读边写
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes)) != -1) {
os.write(bytes, 0, len);
}
// 给服务端写一个结束标记
socket.shutdownOutput();
System.out.println("以下代码是读取响应的结果");
// 5.调用getInputStream,读取响应结果
InputStream is = socket.getInputStream();
byte[] bytes1 = new byte[1024];
int len1 = is.read(bytes1);
System.out.println(new String(bytes1, 0, len1));
// 6.关流
is.close();
os.close();
fis.close();
socket.close();
}
}
import java.util.UUID;
public class Demo293UUID {
public static void main(String[] args) {
String s = UUID.randomUUID().toString();
UUID.randomUUID().toString();
System.out.println("UUID: " + s);
}
}
服务端
package S103InternetFileUpload;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
public class Demo292Server {
public static void main(String[] args) throws Exception {
// 1.创建ServerSocket对象
ServerSocket ss = new ServerSocket(6666);
// 2.调用accept等待客户端的连接
Socket s = ss.accept();
// 3.调用socket中的getInputStream,读取客户端发送过来的图片
InputStream is = s.getInputStream();
//UUID调用randomUUID(),再去调用ToString转成字符串
String string = UUID.randomUUID().toString();// 生成一个十六进制的数据
String name = string + System.currentTimeMillis();
// 4.创建FileOutputStram,将读取过来的图片写在硬盘上
FileOutputStream fos = new FileOutputStream("AllWillBest_Java/src/S103InternetFileUpload/"+name+".jpg");
// 5.边读边写
byte[] bytes = new byte[1024];
int len = 0;
while ((len = is.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
// 6.调用socket中的getOutputStream,给客户端响应结果
System.out.println("以下代码是给客户端的响应结果");
OutputStream os = s.getOutputStream();
os.write("上传成功".getBytes());
// 7.关流
os.close();
is.close();
fos.close();
s.close();
ss.close();
}
}
2.文件上传服务端实现(多线程)
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
public class Demo294ServerThread {
public static void main(String[] args) throws Exception {
// 1.创建ServerSocket对象
ServerSocket ss = new ServerSocket(6666);
while (true) {
// 2.调用accept等待客户端的连接
Socket s = ss.accept();
new Thread(new Runnable() {
@Override
public void run() {
InputStream is = null;
FileOutputStream fos = null;
OutputStream os = null;
try{
// 3.调用socket中的getInputStream,读取客户端发送过来的图片
is = s.getInputStream();
//UUID调用randomUUID(),再去调用ToString转成字符串
String string = UUID.randomUUID().toString();// 生成一个十六进制的数据
String name = string + System.currentTimeMillis();
// 4.创建FileOutputStram,将读取过来的图片写在硬盘上
fos = new FileOutputStream("AllWillBest_Java/src/S103InternetFileUpload/"+name+".jpg");
// 5.边读边写
byte[] bytes = new byte[1024];
int len = 0;
while ((len = is.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
// 6.调用socket中的getOutputStream,给客户端响应结果
System.out.println("以下代码是给客户端的响应结果");
os = s.getOutputStream();
os.write("上传成功".getBytes());
}catch(Exception e){
e.printStackTrace();
}finally {
// 7.关流
Demo295CloseUtils.closeQ(s,fos,is,os);
}
}
}).start();
}
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Demo295CloseUtils {
private Demo295CloseUtils() {
}
public static void closeQ(Socket socket, FileOutputStream fos, InputStream is, OutputStream os){
if(os!=null){
try {
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (socket!=null){
try {
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
3.整体代码实现
① 随机数取名UUID方法
import java.util.UUID;
public class Demo293UUID {
public static void main(String[] args) {
String s = UUID.randomUUID().toString();
UUID.randomUUID().toString();
System.out.println("UUID: " + s);
}
}
② 客户端
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Demo291Client {
public static void main(String[] args) throws Exception {
// 1.创建Socket对象
Socket socket = new Socket("127.0.0.1",6666);
// 2.创建FileInputStream,用于读取本地上的图片
FileInputStream fis = new FileInputStream("D:\\2LFE\\Desktop\\前端三剑客\\css\\CSS.day4\\综合案例-抖音解决方案.jpg");
// 3.调用getOutputStream,用于将读取过来的图片写给服务端
OutputStream os = socket.getOutputStream();
// 4.边读边写
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes)) != -1) {
os.write(bytes, 0, len);
}
// 给服务端写一个结束标记
socket.shutdownOutput();
System.out.println("以下代码是读取响应的结果");
// 5.调用getInputStream,读取响应结果
InputStream is = socket.getInputStream();
byte[] bytes1 = new byte[1024];
int len1 = is.read(bytes1);
System.out.println(new String(bytes1, 0, len1));
// 6.关流
is.close();
os.close();
fis.close();
socket.close();
}
}
③ 服务端常规实现
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
public class Demo292Server {
public static void main(String[] args) throws Exception {
// 1.创建ServerSocket对象
ServerSocket ss = new ServerSocket(6666);
// 2.调用accept等待客户端的连接
Socket s = ss.accept();
// 3.调用socket中的getInputStream,读取客户端发送过来的图片
InputStream is = s.getInputStream();
//UUID调用randomUUID(),再去调用ToString转成字符串
String string = UUID.randomUUID().toString();
String name = string + System.currentTimeMillis();
// 4.创建FileOutputStram,将读取过来的图片写在硬盘上
FileOutputStream fos = new FileOutputStream("AllWillBest_Java/src/S103InternetFileUpload/"+name+".jpg");
// 5.边读边写
byte[] bytes = new byte[1024];
int len = 0;
while ((len = is.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
// 6.调用socket中的getOutputStream,给客户端响应结果
System.out.println("以下代码是给客户端的响应结果");
OutputStream os = s.getOutputStream();
os.write("上传成功".getBytes());
// 7.关流
os.close();
is.close();
fos.close();
s.close();
ss.close();
}
}
④ 服务端多线程实现关闭文件释放资源方法
package S103InternetFileUpload;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Demo295CloseUtils {
private Demo295CloseUtils() {
}
public static void closeQ(Socket socket, FileOutputStream fos, InputStream is, OutputStream os){
if(os!=null){
try {
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (socket!=null){
try {
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
⑤ 服务端多线程实现
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
public class Demo294ServerThread {
public static void main(String[] args) throws Exception {
// 1.创建ServerSocket对象
ServerSocket ss = new ServerSocket(6666);
while (true) {
// 2.调用accept等待客户端的连接
Socket s = ss.accept();
new Thread(new Runnable() {
@Override
public void run() {
InputStream is = null;
FileOutputStream fos = null;
OutputStream os = null;
try{
// 3.调用socket中的getInputStream,读取客户端发送过来的图片
is = s.getInputStream();
//UUID调用randomUUID(),再去调用ToString转成字符串
String string = UUID.randomUUID().toString();// 生成一个十六进制的数据
String name = string + System.currentTimeMillis();
// 4.创建FileOutputStram,将读取过来的图片写在硬盘上
fos = new FileOutputStream("AllWillBest_Java/src/S103InternetFileUpload/"+name+".jpg");
// 5.边读边写
byte[] bytes = new byte[1024];
int len = 0;
while ((len = is.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
// 6.调用socket中的getOutputStream,给客户端响应结果
System.out.println("以下代码是给客户端的响应结果");
os = s.getOutputStream();
os.write("上传成功".getBytes());
}catch(Exception e){
e.printStackTrace();
}finally {
// 7.关流
Demo295CloseUtils.closeQ(s,fos,is,os);
}
}
}).start();
}
}
}