系列文章:
Android Socket 系列更新计划
Android Socket通信(一) – 初识与相遇
Android Socket通信(二) --UDP,单播,广播和多播(组播)
Android Socket通信(三) – TCP 配置和传递基础数据
Android Socket通信(四) – UDP与TCP结合传输数据
Android Socket通信(五) – 实现一个多人聊天室
工程连接 : https://github.com/LillteZheng/SocketDemo
在万物互联的时代,学习 socket 可以加深我们对网络的理解,并写出自己的IM或及时通信,废话不多说,接着开始我们得 socket 之旅吧。
通过这边文章你将学习到:
- 学习 socket
- 了解socekt通信的通用步骤
- 一个简单的聊天实例
一、认识 Socket
socket 是端对端的通信,即网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket;
那两台计算机怎么通信呢 ? 它的通信必要条件为:IP地址,协议,端口号。
- IP地址:两台主机他们需要有一个唯一的标识,用来表示他们所处的身份,所在的位置,这就是IP地址
- 协议:需要有共同的语言,否则就会出现言语不通,无法交流,这就是我们的协议,比如 TCP/IP协议簇
- 端口号:每台主机都需要有相应的端口号,一台主机上可以运行多个应用程序,那如何辨别不同应用程序的通信,我们需要使用端口号来进行区分。
而 socket 通信是基于TCP/IP 网络层上的一种传送方式,我们通常把TCP和UDP称为传输层(图片来源百度图片):
socket 是对TCP/IP的一层抽象,即对传输层的一系列的封装,供开发者去使用,而不用去理解整个网络传输的复杂过程;
二、建立socket 的步骤
在建立 socket ,我们需要分别创建 server 和 client ,用一张图来解释可以如下 (图片来源百度图片):
从上图我们得出 服务端的步骤:
- 获取 ServerSocket 的实例
- 通过 server.accpet() 拿到客户端的 socket 实例
- 通过 socket.getInputStream() 或 socket.getOutputStream() 进行数据传输
客户端步骤:
- 获取 Socket 的实例
- 通过 connect 连接服务器
- 通过 socket.getInputStream() 或 socket.getOutputStream() 进行数据传输
三、实例
理解了上面的连接过程,接着,我们来实现一个简单栗子;
即,客户端通过终端数据,并发送给服务端,服务端拿到数据后,回数据给客户端,以 ‘bye’ 结束
首先先看 客户端代码,首先通过 System.in 拿到终端的数据,然后通过 outputstream 发送给客户端,如下:
/**
* created by zhengshaorui
* time on 2019/6/18
* socket 客户端,从控制台获取信息,发送给服务器端,然后
* 获取服务端的信息并显示
*/
public class Client {
public static void main(String[] args) {
try {
//1.拿到socket实例
Socket socket = new Socket();
//超时时间
socket.setSoTimeout(3000);
//连接本地,端口8000,超时时间为3s
// 2. 通过 connect连接服务器
socket.connect(new InetSocketAddress(Inet4Address.getLocalHost(),8000),3000);
//打印基本信息
System.out.println("客服端信息: "+socket.getLocalAddress()+" 端口: "+socket.getLocalPort());
System.out.println("服务端信息: "+socket.getInetAddress()+" 端口: "+socket.getPort());
//获取终端输入流
BufferedReader cmdReader = new BufferedReader(new InputStreamReader(System.in));
//3.拿到 inputstream 或者 outputstream 进行通信
PrintStream clientPrintStream = new PrintStream(socket.getOutputStream());
BufferedReader clientReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//让它可以循环打印
boolean flag = true;
do {
//获取终端数据,发送给服务器
String msg = cmdReader.readLine();
clientPrintStream.println(msg);
//从服务器读数据
String echo = clientReader.readLine();
if ("bye".equalsIgnoreCase(echo)){
flag = false;
}else{
System.out.println(echo);
}
}while (flag);
//资源释放
cmdReader.close();
clientReader.close();
//socket.close();
System.out.println("我已断开连接");
} catch (IOException e) {
e.printStackTrace();
}
}
}
接着看服务端代码:
/**
* created by zhengshaorui
* time on 2019/6/18
* socket 的服务端,拿到客户端信息后,返回客户端信息的长度
*/
public class Server {
public static void main(String[] args) {
try {
//1.获取 serversocket 实例
ServerSocket serverSocket = new ServerSocket(8000);
System.out.println("服务器准备就绪~");
System.out.println("服务器信息:" + serverSocket.getInetAddress() + " P:" + serverSocket.getLocalPort());
//开始阻塞接受客户端
//2.通过 accept 拿到 客户端的socket
Socket socket = serverSocket.accept();
handleClient handleClient = new handleClient(socket);
handleClient.start();
} catch (Exception e) {
e.printStackTrace();
}
}
static class handleClient extends Thread{
private Socket socket;
private boolean flag = true;
public handleClient(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
super.run();
try {
System.out.println("新的客户端连接了: "+socket.getInetAddress()+" 端口: "+socket.getPort());
//3.通过 inputstream 或 outputstream 进行数据传递
PrintStream printStream = new PrintStream(socket.getOutputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
do {
String msg = br.readLine();
if ("bye".equalsIgnoreCase(msg)){
flag = false;
printStream.println("bye");
}else{
System.out.println("客户端信息: "+msg);
printStream.println("信息长度: "+msg.length());
}
}while (flag);
//释放资源
br.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("客户端: "+socket.getInetAddress()+" 断开连接了");
}
}
}
效果如下 (记得先启动服务端再启动客户端端):
服务端:
客户端: