最近在思考一些软件的实现原理,研究一下那些热门软件是怎么开发出来的,颇有点意思。回顾每天使用的软件,发现平时用的最多的软件应该是通信软件了,如微信、钉钉等,于是在想,这些通信软件是怎么开发出来的,使用了哪些技术?平时大家开发软件的工作大部分是CRUD,对一些不是自己的工作领域,一些底层技术研究的比较少,所以利用业余时间也对一些底层技术和自己感兴趣的软件做些研究。这篇是对通信软件的初探。
Java通信软件的开发技术从socket说起,下面对socket技术做些基础的了解和练习。
先看一下实战的效果图:
一、socket是什么?
网络通信里面,我们都听过TCP/UDP,HTTP,那么Socket是什么?Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。通常可用于通信软件开发,RPC协议开发,文件传输开发等。Socket使用中主要分为ServerSocket和Socket, ServerSocket类表示 Socket 服务器端,Socket 类表示 Socket 客户端。
二、socket的交互流程
socket的使用流程是什么样的呢?
两者之间的交互过程如下:
1.服务器端创建一个 ServerSocket(服务器端套接字),调用 accept() 方法等待客户端来连接。
2.客户端程序创建一个 Socket,请求与服务器建立连接。
3.服务器接收客户的连接请求,同时创建一个新的 Socket 与客户建立连接,服务器继续等待新的请求。
4.使用网络I/O来操作消息的发送和接收。如BufferedReader读/BufferedWriter写。
如下是socket的客户端和服务端的交互示意图。
三、实战演练
了解了socket的知识后,我们来进行一些实战练习。socket的通信实现分为服务端和客户端两个应用,在部署层面是两个独立的应用,我们先实现服务端的代码,如下:
package socketStudy;
import java.io.*;
import java.net.*;
/**
* socket 服务端
* @author xiaoming
* @version 1.0
* @date 2022-01-28
*/
public class CommunicationServer {
public static String socketserver_ip = "127.0.0.1";
public static int socketserver_port = 8881;
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(socketserver_port);
System.out.println("CommunicationServer启动服务器....端口为:"+socketserver_port+" wait connect...");
Socket s = ss.accept();
System.out.println("收到客户端连接,客户端:"+s.getInetAddress().getHostAddress()+"已连接到服务器");
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//读取客户端发送来的消息
String mess = br.readLine();
System.out.println("【收到客户端信息】信息为:"+mess);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bw.write("【服务端】已收到客户端发送消息,消息为:"+mess+"\n");
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
首先,启动服务端socket程序,通过初始化ServerSocket(int port)实例就客户创建一个socket的服务端,port是服务端提供的端口号,对外提供的服务ip地址就是本机的IP地址,这里采用本地连接(127.0.0.1)。然后通过ServerSocket.accept()方法实现监听客户端的连接,之后就是使用BufferedReader、BufferedWriter来收发消息了。
下面在看看socket的客户端代码:
package socketStudy;
import java.io.*;
import java.net.*;
/**
* socket客户端
* @author xiaoming
* @version 1.0
* @date 2022-01-28
*/
public class CommunicationClient {
public static void main(String[] args) {
try {
//连接socket服务端
Socket s = new Socket(CommunicationServer.socketserver_ip,CommunicationServer.socketserver_port);
//构建IO
InputStream inp = s.getInputStream();//输入流,收到的信息
OutputStream outp = s.getOutputStream();//输出流,发出去的消息
//向服务器端发送一条消息
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outp));
bw.write("测试客户端和服务器通信,服务器接收到消息返回到客户端\n");
bw.flush();
//读取服务器返回的消息
BufferedReader br = new BufferedReader(new InputStreamReader(inp));
String mess = br.readLine();
System.out.println("【收到服务器信息】:"+mess);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端首先使用new Socket(String ip,int port)来连接服务端的ip和端口号。然后使用BufferedReader、BufferedWriter来收发消息。先启动CommunicationServer.java,启动成功后,等待连接,会看到日志:
"C:\Program Files\Java\jdk1.8.0_311\bin\java.exe" ...
CommunicationServer启动服务器....端口为:8881 wait connect...
这个时候服务端还没有任何客户端连接,再启动客户端程序,运行CommunicationClient.java,启动成功后,会看到服务端日志更新为如下:
"C:\Program Files\Java\jdk1.8.0_311\bin\java.exe" ...
CommunicationServer启动服务器....端口为:8881 wait connect...
收到客户端连接,客户端:127.0.0.1已连接到服务器
【收到客户端信息】信息为:测试客户端和服务器通信,服务器接收到消息返回到客户端
同时服务端日志展示为:
"C:\Program Files\Java\jdk1.8.0_311\bin\java.exe" ...
【收到服务器信息】:【服务端】已收到客户端发送消息,消息为:测试客户端和服务器通信,服务器接收到消息返回到客户端
这样一个完整的socket的服务端、客户端程序通信就完成了。
四、学习到的知识和问题总结
1、学习到的知识
学到了socket的原理及初步用法,及实战中的容易出错点及纠正方法。
思考:怎么样实现持续的收发消息,及多客户端之间的通信呢?
2、遇到的问题
(1)、起类名字的冲突
自己新建了一个socket服务端类叫ServerSocket,结果和socket的服务端实现类冲突了,尴尬。。。
(2)、发送消息和收到的消息处理搞反了,这个很容易混淆。
好的方法是在参数定义上写清楚一些,并加上注释。
InputStream receiveMsgInputS //输入流,收到的信息
OutputStream sendMsgOutS //输出流,发出去的消息
(3)、程序运行的收发过程混乱
由于是服务端客户端模式,都会来回的收发消息,如果打印的日志不清晰的话,容易搞不清消息收发的过程,网上很多例子都能实现,但是探究其过程,对于初学者还是容易混淆的。建议在每个程序的入口和结尾出打印关键日志,日志中加上处理者的角色,处理的事情,及返回的结果,这样对与学习和排查问题都有很大的好处。