作者 :孙玉昌,昵称【一一哥 】,另外【壹壹哥】也是我哦
千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者
前言
在上一篇文章中,壹哥 给大家简要介绍了什么是Java的网络编程,以及几种常见的网络编程技术。那么在今天的文章中,壹哥就正式开始给大家介绍Socket这种具体的实现技术。在早期的网络编程中,Socket是很常见的实现技术之一,比如早期的聊天室,就是基于这种技术进行实现的。另外现在有些消息推送,也可以基于Socket实现。总之,很多对性能要求不是很高的客户端与服务端之间的通信,都可以基于这种技术进行实现。
------------------------------前戏已做完,精彩即开始----------------------------
全文大约【3000】 字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考......
配套开源项目资料
Github: github.com/SunLtd/Lear...
Gitee: gitee.com/sunyiyi/Lea...
一. Socket编程
1. 简介
Socket编程是基于TCP/IP协议的网络编程技术,它给我们提供了一种可以用于网络通信的机制,让我们能在不同的计算机之间进行数据交换。我们可以利用Socket编程实现客户端/服务器程序的开发,如聊天室、FTP客户端等项目。
2. 通信流程
对于Socket编程,我们要重点搞清楚客户端与服务器端之间的通信流程。
在Socket编程中有两种类型的Socket:服务器Socket和客户端Socket。服务器Socket可以在服务器上创建用于监听客户端请求的端口,客户端Socket则可以在客户端上创建用于连接服务器的Socket。客户端Socket向服务器Socket发送请求,服务器Socket可以接收该请求,并创建一个新的Socket用于与客户端通信。通过这种方式,客户端和服务器端之间就可以进行数据交换。
在Socket编程中,客户端和服务器之间会通过TCP/IP协议进行通信。客户端Socket首先回连接到服务器Socket的IP地址和端口号,这样就会建立起一个TCP连接。一旦连接建立,客户端和服务器之间就可以进行数据传输。数据会被分割成数据包,并通过TCP/IP协议在客户端和服务器之间传输。
然后服务器Socket会在服务器端创建一个用于监听客户端请求的端口,客户端Socket则在客户端上创建用于连接服务器的Socket。客户端Socket向服务器Socket发送连接请求,服务器Socket接收该请求并创建一个新的Socket用于与客户端通信。通过这种方式,客户端和服务器端之间就可以进行数据交换。
这样,客户端和服务器端之间就通过TCP/IP协议实现了Socket通信。
3. 核心API
我们可以使用java.net包中的API来实现Socket编程,这些常用的API包括:
- ServerSocket类:用于创建服务器端Socket,监听客户端发来的请求。
- Socket类:用于创建客户端Socket,可以连接服务器Socket。
- InputStream和OutputStream类:用于在Socket之间传输数据的输入输出流。
4. 基本案例-单向通信
接下来壹哥先给大家编写一个可以实现单向通信的基本案例,包括一个服务器端和一个客户端。这个案例中,客户端给服务器端发送一条消息,然后服务器把客户端发来的消息打印出来,代码如下:
4.1 服务器端
下面是服务器端的代码案例。在本案例中,壹哥主要是利用ServerSocket对象定义了一个服务器,并通过accept()方法来获取与该服务器绑定的Socket客户端对象。这里要注意端口号"1234"是我们自己随意定义的,只要不与其他程序的端口号重合即可。然后我们可以在Socket客户端对象上通过getInputStream()方法来获取一个InputStream输入流,进而读取客户端发来的消息。最后大家要记得把各种IO流资源释放。
java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 一一哥Sun
* @company 千锋教育
*/
public class MySocketServer {
public static void main(String[] args) throws IOException {
//设置服务器的端口号
int portNumber = 1234;
// 创建服务器套接字并绑定端口号
ServerSocket serverSocket = new ServerSocket(portNumber);
//获取与ServerSocket关联的Socket客户端对象
Socket acceptSocket = serverSocket.accept();
// 服务器接收客户端发来的消息
InputStream serverInputStream = acceptSocket.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(serverInputStream));
String response = in.readLine();
if (response != null) {
System.out.println("服务器接收客户端发来的消息===>: " + response);
}
// 关闭套接字和流
serverSocket.close();
acceptSocket.close();
serverInputStream.close();
}
}
大家要注意,壹哥在今天的案例中,没有使用循环来一直进行消息的收发,如果我们想实现不间断的消息收发,可以把相关代码写在循环体中。所以在今天的案例中,消息收发一次之后,项目就会停掉。
4.2 客户端
接着壹哥 又定义了一个客户端程序。在该程序中,壹哥 定义了一个Socket客户端对象,该对象通过IP地址和端口号来关联服务端对象。因为壹哥的项目,客户端和服务端是在同一台机器上,所以这里的IP地址我们可以使用localhost,当然也可以用服务端的实际IP地址。然后利用字符流和字节输出流给服务端发送信息,最后释放IO流资源。
java
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
/**
* @author 一一哥Sun
* @company 千锋教育
*/
public class MySocketClient {
public static void main(String[] args) throws IOException {
try {
// 创建Socket对象并连接到服务器,关联服务器的ip地址与端口号
Socket socket = new Socket("localhost", 1234);
// 创建输入输出流,通过套接字发送和接收数据
Scanner scanner = new Scanner(System.in);
String nextLine = scanner.nextLine();
// 输出流,客户端向服务器发送消息
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println(nextLine);
// 关闭套接字和流
out.close();
scanner.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这个案例中,壹哥 主要是利用ServerSocket、Socket和IO流这三种API,就实现了客户端给服务端发送消息的功能。但是这个案例中,我们只能是客户端给服务端发送消息,服务端却不能给客户端回复消息,所以接下来壹哥要把这个案例改进一下,实现客户端与服务端之间互相传递消息。
5. 改进案例-双向通信
接下来我们就把上面的案例改进一下,实现客户端与服务器端之间的双向通信,即客户端给服务器端发送消息,服务器端收到消息之后,再给客户端返回消息。
5.1 服务器端
在下面的代码中,壹哥把服务器端的代码改进了一下,在if语句中增加了利用OutputStream向客户端返回信息的代码,如下所示:
java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 一一哥Sun
* @company 千锋教育
*/
public class MyServer {
public static void main(String[] args) throws IOException {
int portNumber = 1234;
// 创建服务器套接字并绑定端口号
ServerSocket serverSocket = new ServerSocket(portNumber);
// 注意:服务器只能接受一次客户端!用该socket对象既可以接收客户端发来的消息,也可以给客户端回复消息
Socket acceptSocket = serverSocket.accept();
// 服务器接收客户端发来的消息
InputStream serverInputStream = acceptSocket.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(serverInputStream));
String response = in.readLine();
if (response != null) {
System.out.println("服务器接收客户端发来的消息===>: " + response);
// 服务器向客户端发送响应信息
OutputStream serverOutputStream = acceptSocket.getOutputStream();
String serverResponse = "我是服务器,你的消息已收到!";
serverOutputStream.write(serverResponse.getBytes());
serverOutputStream.flush();
serverOutputStream.close();
}
// 关闭套接字和流
serverSocket.close();
acceptSocket.close();
serverInputStream.close();
//serverOutputStream.close();
}
}
5.2 客户端
在下面的代码中,壹哥把客户端的代码也改进了一下,主要是增加了利用BufferedReader和InputStream,读取服务器返回信息的代码,如下所示:
java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
/**
* @author 一一哥Sun
* @company 千锋教育
*/
public class MyClient {
public static void main(String[] args) throws IOException {
try {
//创建Socket对象并连接到服务器
Socket socket = new Socket("localhost", 1234);
//创建输入输出流,通过套接字发送和接收数据
Scanner scanner=new Scanner(System.in);
String nextLine = scanner.nextLine();
//输出流,客户端向服务器发送消息
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println(nextLine);
//输入流,客户端从服务器接收消息
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String response = in.readLine();
System.out.println("Server服务器返回的响应信息===>: " + response);
//关闭套接字和流
out.close();
in.close();
scanner.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
经过以上代码的改造,我们就实现了服务器与客户端之间的双向通信,大家可以把壹哥的代码案例运行起来看看效果。
6. 注意事项
大家要注意,在进行Socket通信开发时,稍有不慎可能就会出现各种问题,所以我们要注意以下事项:
- 在每个Socket连接中,我们都应该严格按照协议规定的格式进行数据的发送和接收,否则就可能会导致数据传输失败或被误解。
- 在Socket编程中,应该使用多线程或异步机制等技术来避免阻塞。如果阻塞时间过长,可能会导致客户端或服务器崩溃。在上面的案例中,壹哥是把收发消息的代码之间写在了主线程中,其实我们可以把这种耗时的操作放在Thread或线程池中进行实现。
- 服务器端应该可以同时处理多个客户端的请求,否则有可能会导致客户端的请求被拒绝或服务器崩溃。
- 我们要保证Socket编程的保安全性,例如防止黑客攻击、拒绝服务攻击等恶意行为。
- 我们还应该有适当的错误处理,例如必须处理网络连接失败、数据传输的失败等异常情况。
除了以上几点注意事项,还有其他一些细节需要注意。在Socket编程中,必须对网络通信有深入的理解和掌握,才能确保程序的正确性和安全性。
------------------------------正片已结束,来根事后烟----------------------------
二. 结语
今天的文章,壹哥主要是给大家介绍了Socket编程的实现过程。其实Socket通信主要就是分为服务器端和客户端,有着比较清晰的实现逻辑,学习起来并不难,大家重点理解和掌握Socket通信的实现流畅即可。
另外如果你独自学习觉得有很多困难,可以加入壹哥的学习互助群,大家一起交流学习。