2.网络编程
2.1. 通信协议
-
TCP、UDP对比
-
TCP 打电话
-
连接,稳定
-
三次握手,四次挥手
三次握手 A: 你瞅啥? B: 瞅你咋地? A:干一场! 四次挥手 A:我要走了 B: 你真的要走了吗? B:你真的真的要走了吗? A:我真的要走了
-
客户端、服务端
-
传输完成,释放连接,效率低
-
-
UDP 发短信
- 不连接,不稳定
- 客户端,服务端,没有明确的界限
- 不管有没有准备好,都可以发给你
- 导弹
- DDOS:洪水供给!(饱和攻击)
-
2.2. Tcp上传测试
1、TcpUploadClient.java
package com.hzs.basic.inet;
import java.io.*;
import java.net.Inet4Address;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
/**
* @author Cherist Huan
* @version 1.0
* @date 2021/6/8 11:39
* @note 文件上传客户端
*/
public class TcpUploadClient {
public static void main(String[] args) throws IOException {
// 1、创建一个Socket连接
Socket socket = new Socket(Inet4Address.getByName("127.0.0.1"),9999);
// 2、创建一个输出流
OutputStream os = socket.getOutputStream();
// 3、读取文件
// FileInputStream fis = new FileInputStream(new File(String.valueOf(TcpUploadClient.class.getResource("6.jpg"))));
// URL resource = TcpUploadClient.class.getResource("/images/6.jpg");
// FileInputStream fis = new FileInputStream(resource.getPath());
File file = new File("java-test-questions-06/src/main/resources/images/6.jpg");
// File file = new File("images/6.jpg");
System.out.println(file.getAbsolutePath());
FileInputStream fis = new FileInputStream(file);
// 4、写出文件
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer))!= -1)
{
os.write(buffer,0,len);
}
// 通知服务器,我已经传输完毕了
socket.shutdownOutput(); // 我已经传输完毕
// 接受服务器的响应,确定服务器接受完毕,才能关闭连接
InputStream is2 = socket.getInputStream();
byte[] buffer2 = new byte[1024];
int len2;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while((len2 = is2.read(buffer2))!= -1)
{
baos.write(buffer2,0,len2);
}
System.out.println(baos.toString());
// 5、关闭资源
baos.close();
fis.close();
os.close();
socket.close();
}
}
2、TcpUploadServer.java
package com.hzs.basic.inet;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
/**
* @author Cherist Huan
* @version 1.0
* @date 2021/6/8 11:39
* @note 文件上传服务端
*/
public class TcpUploadServer {
public static void main(String[] args) throws IOException {
// 1、创建ServerSocket
ServerSocket serverSocket = new ServerSocket(9999);
// 2、创建Socket监听
Socket socket = serverSocket.accept();
// 3、获取输入流
InputStream is = socket.getInputStream();
// 4、文件输出
// URL resource = TcpUploadClient.class.getResource("/images/6_receive.jpg");
// //FileOutputStream fos = new FileOutputStream(new File(resource.getPath()));
// FileOutputStream fos = new FileOutputStream(resource.getPath());
File file = new File("java-test-questions-06/src/main/resources/images/6receive.jpg");
//File file = new File("images/6_receive.jpg");
FileOutputStream fos = new FileOutputStream(file);
byte[] buffer;
buffer = new byte[1024];
int len;
while((len = is.read(buffer))!= -1)
{
fos.write(buffer,0,len);
}
// 通知客户端,我已经接受完毕
OutputStream os = socket.getOutputStream();
os.write("服务端返回,服务端已经接受完毕了".getBytes());
// 5、关闭资源
os.close();
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}
总结:
-
客户端
- 建立socket连接
- 创建一个输出管道流
- 读取需要上传的文件
- 将文件写出到管道流
- 通知服务器,我已经传输完毕
- 接受服务器的响应,确定服务器接受完毕,才能关闭连接
- 关闭资源
-
服务端
- 建立ServerSocker端口服务
- 创建Socket监听,返回Socket
- 获取输入流
- 获取输入流中文件输出
- 通知客户端,我已经接受完毕
- 关闭资源
2.3. Udp 传输
1、UdpClient.java
package com.hzs.basic.inet;
import java.io.IOException;
import java.net.*;
/**
* @Author Cherist Huan
* @Date 2021/6/10 10:41
* @Version 1.0
*/
public class UdpClient {
public static void main(String[] args) throws IOException {
// System.out.println(("AB".getBytes()).length);//2
// 1、建立一个Socket
DatagramSocket socket = new DatagramSocket();
// 2、建包
String msg = "Hello Cherist Huan!";
InetAddress byName = Inet4Address.getByName("127.0.0.1");
int port = 9090;
DatagramPacket datagramPacket = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,byName,port);
// 3、发送包
socket.send(datagramPacket);
// 4、关闭流
socket.close();
}
}
2、UdpServer.java
package com.hzs.basic.inet;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
* @Author Cherist Huan
* @Date 2021/6/10 10:57
* @Version 1.0
*/
public class UdpServer {
public static void main(String[] args) throws IOException {
// 1、开放端口
DatagramSocket datagramSocket = new DatagramSocket(9090);
// 2、接受数据包
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
datagramSocket.receive(packet);// 阻塞式接受
System.out.println(new String(packet.getData(),0,packet.getLength()));
// 关闭流
datagramSocket.close();
}
}
2.4. Udp聊天室(多线程)
1、TalkSend.java
package com.hzs.basic.inet;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
/**
* @Author Cherist Huan
* @Date 2021/6/10 15:24
* @Version 1.0
*/
public class TalkSend implements Runnable {
DatagramSocket socket = null;
BufferedReader reader = null;
private int fromPort;
private int toPort;
private String toIp;
public TalkSend(int fromPort, int toPort, String toIp) {
this.fromPort = fromPort;
this.toPort = toPort;
this.toIp = toIp;
try {
socket = new DatagramSocket(fromPort);
reader = new BufferedReader(new InputStreamReader(System.in));
} catch (SocketException e) {
e.printStackTrace();
}
}
public void run() {
while(true)
{
try {
String data = reader.readLine();
byte[] dataBytes = data.getBytes();
DatagramPacket packet = new DatagramPacket(dataBytes,0,dataBytes.length,new InetSocketAddress(this.toIp,this.toPort));
socket.send(packet);
if(data.equals("bye")){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
2、TalkReceive.java
package com.hzs.basic.inet;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
* @Author Cherist Huan
* @Date 2021/6/10 15:44
* @Version 1.0
*/
public class TalkReceive implements Runnable{
DatagramSocket socket = null;
private int port;
private String msg;
public TalkReceive(int port,String msg){
this.port = port;
this.msg = msg;
try {
socket = new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
}
}
public void run() {
while(true){
try {
byte[] container = new byte[1024];
DatagramPacket packet = new DatagramPacket(container, 0, container.length);
socket.receive(packet);//阻塞式接受包裹
// 断开连接 bye
byte[] data = packet.getData();
String receiveData = new String(data,0,data.length);
System.out.println(msg+":"+receiveData);
if(receiveData.equals("bye"))
{
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
3、TalkStudent.java
package com.hzs.basic.inet;
/**
* @Author Cherist Huan
* @Date 2021/6/10 15:56
* @Version 1.0
*/
public class TalkStudent {
public static void main(String[] args) {
// 开启两个线程
new Thread(
new TalkSend(7777,9999,"localhost")
).start();
//学生端接受线程端口(服务端口 8888)
new Thread(
new TalkReceive(8888,"老师说")
).start();
}
}
4、TalkTeacher.java
package com.hzs.basic.inet;
/**
* @Author Cherist Huan
* @Date 2021/6/10 16:04
* @Version 1.0
*/
public class TalkTeacher {
public static void main(String[] args) {
// 开启两个线程
new Thread(
new TalkSend(6666,8888,"localhost")
).start();
//老师端接受线程端口(服务端口 9999)
new Thread(
new TalkReceive(9999,"学生说")
).start();
}
}
2.5 对比总结
Java网络编程中,TCP(传输控制协议)和UDP(用户数据报协议)是两种主要的传输层协议。它们各有特点和适用场景。
TCP传输
特点:
- 面向连接:TCP在传输数据之前需要先建立连接,传输完成后需要断开连接。
- 可靠传输:TCP通过序列号、确认应答、超时重传等机制确保数据的可靠传输。
- 流量控制:TCP通过滑动窗口机制进行流量控制,避免发送方发送速率过快导致接收方处理不过来。
- 拥塞控制:TCP通过慢开始、拥塞避免、快重传、快恢复等算法进行拥塞控制,避免网络拥塞。
应用场景:
- 需要可靠传输的应用,如文件传输、电子邮件等。
- 对数据传输顺序有要求的应用,如网页浏览、在线视频等。
UDP传输
特点:
- 无连接:UDP在传输数据之前不需要建立连接,每个数据报都是一个独立的信息。
- 不可靠传输:UDP不保证数据的可靠传输,不进行流量控制和拥塞控制。
- 开销小:由于UDP协议简单,传输开销小,适合实时性要求高的应用。
应用场景:
- 实时性要求高的应用,如音频、视频流等。
- 允许一定程度上数据丢失的应用,如实时游戏、实时股市行情等。