1.背景介绍

  笔者在最近的项目中需要使用到TCP连接进行数据通信,但此前笔者对于TCP通信在项目中的应用一窍不通,更别提听说到要直接用TCP连接了,当时我真的是脑子嗡了一下。不过平复了一下情绪去做了以后,发现这件事情其实并没有想象中那么困难,甚至还挺有意思的,这样一个心理的过程我觉得在面对难题的时候尤其容易产生,我们太容易害怕了,如果勇敢点,我们做了一段时间以后,甚至会笑嘻嘻地说:“嘿!我竟然会为这么个小东西害怕,太好笑了!”

  这里笔者啰嗦几句,权当是热身,并不影响后续的技术介绍,热身完毕,我们该进入正题了。

2.TCP简单介绍

  传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793 [1] 定义。TCP通信一般指客户端和服务端通信。

  在Java中,一般使用SocketServer和Socket这两个类实现TCP通信,前者为服务端的一个实体,而后者可以认为是一种对连接的封装。一般来说,需要先启动服务端,然后客户端才能向服务端发送连接请求,连接成功后,两端就可以互相通信了。

3.Java中TCP通信流程

  • 服务端:
  1. 创建ServerSocket对象,绑定监听端口。
  2. 通过accept()方法监听客户端请求。
  3. 连接建立后,通过输入流读取客户端发送的请求信息。
  4. 通过输出流向客户端发送响应信息。
  5. 关闭响应的资源。
  • 客户端:
  1. 创建Socket对象,指明需要连接的服务器的地址和端口号。
  2. 连接建立后,通过输出流向服务器发送请求信息。
  3. 通过输入流获取服务器响应的信息。
  4. 关闭相应资源。

4.示例代码

服务端:

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author: LJ
 * @description:TCP服务端简单实现
 **/
public class TCP_Server {
    public static void main(String[] args)throws IOException
    {
        //监听端口
        int port = 30000;
        //创建一个ServerSocket, 用于监听客户端Socket的连接请求
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("server启动成功,等待客户端连接...");

        //server等待连接的到来
        Socket socket = serverSocket.accept();
        //将Socket对应的输出流包装成printStream
        PrintStream ps = new PrintStream(socket.getOutputStream());
        ps.println("You have received message form server!");

        InputStream inputStream = socket.getInputStream();
        byte[] bytesFromClient = new byte[1024];
        int len = 0;
        StringBuilder sb = new StringBuilder();
        while ((len = inputStream.read(bytesFromClient))!=-1){
            sb.append(new String(bytesFromClient, 0 , len));
        }
        System.out.println("get message from client: "+ sb.toString());

        //关闭输出流,关闭socket
        inputStream.close();
        ps.close();
        socket.close();
    }
}

客户端:

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * @author: LJ
 * @description:TCP客户端简单实现
 **/
public class TCP_Client {
    public static void main(String[] args) throws IOException {
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        OutputStream os = null;
        OutputStreamWriter osw = null;
        PrintWriter pw = null;
        try{
            //建立连接
            Socket socket = new Socket("localhost", 30000);
            System.out.println("开启Socket线程");
            //获取字节输出流
            os = socket.getOutputStream();
            //将输出流包装为打印流
            pw = new PrintWriter(os);
            pw.write("Hi server! This is message from client!");
            pw.flush();
            //关闭输出流
            socket.shutdownOutput();
            //获取字节输入流
            is=socket.getInputStream();
            br=new BufferedReader(new InputStreamReader(is));
            String message =null;
            while ((message = br.readLine())!=null){
                System.out.println("我是客户端,服务器返回消息:"+message);
            }

            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            br.close();
            is.close();
            pw.close();
            os.close();
        }
    }
}

5.实验

  编写好代码以后,我们可以开始测试代码了,首先启动服务器。(需要注意的是,两个程序需要同时运行,也就是说,你得启动两个集成开发环境保证客户端和服务端同时运行)控制台打印如下:

server启动成功,等待客户端连接...

接着启动客户端,这时服务端打印如下:

server启动成功,等待客户端连接...
get message from client: Hi server! This is message from client!

客户端打印如下:

开启Socket线程
我是客户端,服务器返回消息:You have received message form server!

  实验结束,我们看到TCP通信成功了,也就是说我们编写的代码成功了!当然,这只是最基础的TCP通信,一般来说,你的服务端不可能只服务一个客户端,所以你需要为每一个连接创建一个线程,更复杂的情况需要使用一个线程池来保证运行效率。另外,TCP服务端如何检测TCP客户端断开连接也是一个令人头疼的问题,因为TCP连接是一个长连接,而默认情况下这个连接的持续时间会长达2个小时,如果断开连接而程序没有检测到,那么为了维持这个连接就浪费了很多的资源,这不是一件令人高兴的事情。

  后续如果还有时间的话,最后提到的这两个问题,笔者也会给出自己实际采用的解决方案,不过那就不知道会是什么时候了,或许鸽了也说不定 😃 (靠,我的符号怎么变了,补一下— : ))。


参考资料:

Java–Socket编程TCP通信 - 知乎 (zhihu.com)

Java实现TCP通信 - 简书 (jianshu.com)