likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 23

前言

在上一篇文章中,壹哥给大家简要介绍了什么是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流资源释放。

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流资源。

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向客户端返回信息的代码,如下所示:

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,读取服务器返回信息的代码,如下所示:

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通信的实现流畅即可。

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