从零开始学Java之如何利用Socket实现网络通信?

作者 :孙玉昌,昵称【一一哥 】,另外【壹壹哥】也是我哦

千锋教育高级教研员、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通信的实现流畅即可。

另外如果你独自学习觉得有很多困难,可以加入壹哥的学习互助群,大家一起交流学习。

相关推荐
骄马之死5 小时前
SpringMVC + SpringBoot 核心知识点总结
java·spring boot·后端
GoGeekBaird6 小时前
Anthropic技能"(Skills)的经验分享
后端
王码码20356 小时前
多台服务器怎么统一看状态?Beszel 轻量监控,搭起来不费事
运维·服务器·后端·安全·阿里云·接口·web
郑洁文7 小时前
基于Spring Boot的流浪动物救助网站
java·spring boot·后端·毕设·流浪动物救助
螺丝钉code7 小时前
JAVA项目 Claude code CLAUDE.md 到底应该怎么写
java·人工智能·claude code
指令集梦境8 小时前
Cursor + Spring Boot实战:从零写一个RESTful API
spring boot·后端·restful
摇滚侠9 小时前
Maven 入门+高深 单一架构案例 54-59
java·架构·maven·intellij-idea
VidDown9 小时前
Webhook 调试器:让第三方回调“原形毕露”
java·开发语言·javascript·编辑器·postman
码云之上9 小时前
聊聊如何设计一个高效、稳定的 Node.js 接入层
前端·后端·node.js
折哥的程序人生 · 物流技术专研9 小时前
Java 23 种设计模式:从踩坑到精通 | 原型模式 —— 克隆对象,深拷贝与浅拷贝的坑你踩过吗?
java·设计模式·架构·原型模式·单一职责原则