一、概述
前一篇博客我们了解了TCP通信协议的基本原理以及实现过程,因此需要更进一步,即实现双方都能够实时通信。
二、原理
在上一篇博客中说过,使用Java Socket模型中的socket 对象去监听某个对象的连接,通过获取该对象的socket获取流信息,但问题在于如何实现消息的实时收发?
1、单线程收发消息的不足:
当我们创建一个客户端到服务段的socket连接之后,需要设置对象的IO流,但在主函数中,这些方法是被线性执行的,因此两端的IO流都是依此执行的,每个方法必须等待上一个方法结束后才能执行,这样收发消息的效率比较低。因此我们可以通过多线程将这些功能独立出来,每个线程只负责运行自己的功能,这样就可以突破线性执行的缺点。
2、实现过程:
在创建对象的IO流时,先将对应的功能放到线程中,并通过无限循环该功能实现消息的实时收发。
三、代码实现
1、服务器对象
public class Server {
//初始化服务器的端口以及socket对象
ServerSocket socket = null;
int port = 58888;
//初始化服务器
public void initServer(){
try {
socket = new ServerSocket(port);
} catch (IOException e) {
throw new RuntimeException (e);
}
}
//检测端口是否有对象连接
public Socket listener(){
try {
return socket.accept();
} catch (IOException e) {
throw new RuntimeException (e);
}
}
public void init(){
initServer();
Socket newSocket = listener();
//IO流线程初始化并启动
ReciveMessageThread reciveMessageThrea = new ReciveMessageThread(newSocket);
SendMessageThread sendMessageThread = new SendMessageThread(newSocket);
reciveMessageThrea.start();
sendMessageThread.start();
}
public static void main(String[] args) {
new Server().init();
}
}
2、IO流线程
//消息接收端
public class ReciveMessageThread extends Thread{
//初始化对象
Socket socket = null;
InputStream in = null;
static String returnMsg;
public ReciveMessageThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
in = socket.getInputStream();
System.out.println("in初始化成功");
} catch (IOException e) {
throw new RuntimeException(e);
}
while (true){
System.out.println("开始接收数据");
try {
int msgLen = in.read();
byte [] msg = new byte[msgLen];
in.read(msg);
returnMsg = new String(msg , 0 , msgLen);
} catch (IOException e) {
throw new RuntimeException (e);
}
}
}
}
//消息发送端
public class SendMessageThread extends Thread{
Socket socket = null;
OutputStream out = null;
public SendMessageThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
out = socket.getOutputStream();
System.out.println("out初始化成功");
} catch (IOException e) {
e.printStackTrace();
}
while (true){
System.out.println("请输入发送的信息");
Scanner sc = new Scanner(System.in);
String msg = sc.next();
MessageEncode messageEncode = new MessageEncode(msg);
try {
out.write(1);
out.write(messageEncode.encoding().length);
out.write(messageEncode.encoding());
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3、消息编解码
//消息编码
public class MessageEncode {
String msg;
public MessageEncode(String msg){
this.msg = msg;
}
//将消息转换为字节并存入字节数组
public byte[] encoding(){
byte [] data = this.msg.getBytes();
return data;
}
}
//消息解码
public class MessageDecode {
InputStream inputStream;
public MessageDecode(InputStream inputStream){
this.inputStream = inputStream;
}
//通过IO流获取发送的数组,解码并输出
public String decoding(){
byte [] reciveMsg = new byte[1024];
try {
this.inputStream.read(reciveMsg);
int len = reciveMsg.length;
System.out.println(len);
String newMsg = new String(reciveMsg , 0 , len);
return newMsg;
} catch (IOException e) {
throw new RuntimeException (e);
}
}
}
4、客户端连接
public class Client_A {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1" , 58888);
InputStream in = socket.getInputStream();
byte b [] = new byte[1024];
while (true){
int len = 0;
len = in.read(b);
String newStr = new String(b , 0 , len);
System.out.println(newStr);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、运行效果
服务器监听到客户端连接
服务器端消息发送
客户端消息接收