Java实现TCP通信——发弹幕案例
TCP通信可以实现双方相互接收发送消息,初学TCP通信,从简入难,先实现一方可以接收多方消息(一方作为服务端,多方作为客户端),即类似于观看视频的用户发送多条弹幕,同时其他用户也可以发送多条弹幕,可视作客户端;屏幕展现的所有弹幕,可视作服务端。
发弹幕案例,主要包含IO流知识点、线程知识点、TCP通信知识点。接下来先总结一些网络编程、TCP协议、UDP协议基础知识。通过编写发弹幕案例,进行复习巩固。
文章目录
- Java实现TCP通信——发弹幕案例
- 实现网络编程关键的三要素
- *TCP协议特点*
- UDP协议特点
- -TCP三次握手确立连接
- -TCP三次握手确立连接TCP四次挥手断开连接
- TCP通信模式
- TCP通信的基本原理
- 步骤分析
- a. 客户端发送弹幕步骤分析
- b. 服务端发送弹幕步骤分析
- 1. 客户端代码
- 2. 服务端代码
- 3. 多个客户端并发配置操作
- 4. 运行结果
实现网络编程关键的三要素
1. IP地址:设备在网络中的地址,是唯一的标识。
2. 端口:应用程序在设备中唯一的标识。
3. 协议: 数据在网络中传输的规则,常见的协议有UDP协议和TCP协议。
- TCP(Transmission Control Protocol) :传输控制协议
- UDP(User Datagram Protocol):用户数据报协议
TCP协议特点
- 使用TCP协议,必须双方先建立连接,它是一种面向连接的可靠通信协议。
- 传输前,采用“三次握手”方式建立连接,所以是可靠的 。
- 在连接中可进行大数据量的传输 。
- 连接、发送数据都需要确认,且传输完毕后,还需释放已建立的连接,通信效率较低。
- 对信息安全要求较高的场景,例如:文件下载、金融等数据通信。
UDP协议特点
- UDP是一种无连接、不可靠传输的协议。
- 将数据源IP、目的地IP和端口封装成数据包,不需要建立连接
- 每个数据包的大小限制在64KB内,数据不安全,易丢失数据
- 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
- 可以广播发送 ,发送数据结束时无需释放资源,开销小,速度快。
- 语音通话,视频会话等。
本文重点学习TCP通信,TCP是一种面向连接的可靠通信协议,对于它的“三次握手"确定连接、”四次挥手“断开连接的具体情况,如下图
-TCP三次握手确立连接
原理转换小剧场:
-TCP三次握手确立连接TCP四次挥手断开连接
原理转换小剧场:
TCP通信模式
TCP通信的基本原理
- 客户端怎么发,服务端就应该怎么收。
- 客户端如果没有消息,服务端会进入阻塞等待。
- Socket一方关闭或者出现异常、对方Socket也会失效或者出错。
需求:多个客户端可以发多个弹幕给一个服务端
根据TCP通信模式、基本原理,可尝试编写代码:分客户端、服务端两部分进行编写代码
步骤分析
a. 客户端发送弹幕步骤分析
- 创建客户端的Socket对象,请求与服务端的连接。
- 使用socket对象调用getOutputStream()方法得到字节输出流。
- 使用字节输出流完成数据的发送。
- 使用死循环,客户端可以不断发送弹幕。
b. 服务端发送弹幕步骤分析
- 创建ServerSocket对象,注册服务端端口。
- 调用ServerSocket对象的accept()方法,等待客户端的连接,并得到Socket管道对象。
- 通过Socket对象调用getInputStream()方法得到字节输入流、完成数据的接收。
- 主线程定义了循环负责接收客户端Socket管道连接
- 每接收到一个Socket通信管道后分配一个独立的线程负责处理它。
注意:Socket一方关闭或者出现异常、对方Socket也会失效或者出错。
1. 客户端代码
选择合适的IO流,提高程序性能,客户端此时只是输出文本,OutputStream 低级流转换为PrintStream 打印流最佳。
注意:写出数据要即使刷新 flush()
public class ClientDemo {
public static void main(String[] args) {
try {
System.out.println("=============客户端=====================");
//创建一个通道,请求有服务端的连接,参数需要填写要连接的管道
Socket socket = new Socket("127.0.0.1",7777);
//创建一个输出流
OutputStream os = socket.getOutputStream();
//将字节输出流转换为高级流,此处打印流为最佳选项
PrintStream ps = new PrintStream(os);
Scanner scanner = new Scanner(System.in);
//进行多次输出
while (true) {
System.out.println("请说:");
//进行添加要打印的数据
String msg = scanner.nextLine();
ps.println(msg);
//进行刷新数据
ps.flush();
}
//此时不需要关闭,因为TCP 通信,可能数据没有传输过去,
// 现在进行关闭,会造成数据的丢失
// //关闭管道
// ps.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 服务端代码
2.1 创建 ServerReaderThread 类,主线程每接收到一个Socket通信管道后,均创建ServerReaderThread 类的对象,目的是为其分配一个独立的线程负责处理它,这样可以实现多个客户端同时发送多个弹幕(消息)给服务端。
在传输内容方式,选择合适的IO流进行编写代码,以提高程序性能。在此处,只是进行文字传输,可以将InputStream 转换为BufferedReader,将字节输入流转换为缓存字符输入流,不仅读取速度更快,而且BufferedReader 包含独有的API,readLine()读取字符内容更加方便。
public class ServerReaderThread extends Thread{
//定义接收通道
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//创建一个字节输入流,进行流入数据
InputStream is = socket.getInputStream();
//将低级的字节输入流,转换为高级流,此时缓存字符输入流最为合适
//注意缓存字符输入流,不能直接接受字节输入流,应将其转换为字符输入流
BufferedReader bis = new BufferedReader(new InputStreamReader(is));
//定义一个字符串,利用字符串进行输出一行数据
String msg;
//进行检验,输出数据
while ((msg = bis.readLine()) != null){
System.out.println(socket.getRemoteSocketAddress()+"发送了:"+msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.2 服务端代码
注意:继承Thread创建的线程,需要调用start(),进行启动,否则不会开始这个线程。
public class ServerDemo {
public static void main(String[] args) throws Exception {
System.out.println("=============服务端=====================");
//服务端创建一个端口号
ServerSocket serverSocket = new ServerSocket(7777);
//定义一个死循环,由主线程不断的接收客户端的socket管道连接
while (true) {
//每次收到一个客户端的socket管道,交给一个独立的子线程负责读取信息
Socket socket = serverSocket.accept();
//开始创建独立的子线程处理socket
new ServerReaderThread(socket).start();
}
}
}
3. 多个客户端并发配置操作
发弹幕案例,是允许多个客户端一起发送内容,所以重新编辑配置,可以多个客户端并发进行。具体修改操作如下图
先运行服务端,在运行客户端。
此时,我只开了四个客户端,看个人需求需要开几个客户端均可。
4. 运行结果
=============服务端=====================
/127.0.0.1:1646发送了:锦瑟无端五十弦
/127.0.0.1:1651发送了:一线一柱思华年
/127.0.0.1:1659发送了:庄生晓梦迷蝴蝶
/127.0.0.1:1672发送了:望帝春心托杜鹃
/127.0.0.1:1646发送了:沧海月明珠有泪
/127.0.0.1:1651发送了:蓝田日暖玉生烟
/127.0.0.1:1659发送了:此情可待成追忆
/127.0.0.1:1672发送了:只是当时已惘然
=============客户端=====================
请说:
锦瑟无端五十弦
请说:
沧海月明珠有泪
请说: