Socket所遇到的坑

本文记录使用Socket通信时所遇到坑,不断更新。

目前记录三个问题:

  • 建立Socket连接
  • 使用输入流和输出流进行通信
  • 使用心跳保持Socket连接

建立Socket连接

Socket连接需要一个ServerSocket充当服务器,还有许多Socket作为客户端来连接ServerSocket. 在Eclipse中代码如下:

服务器端:

                Socket socket;
                System.out.println("wait for a client.");
                socket = serverSocket.accept();
                System.out.println("accept a socket.");
                writer = new ObjectOutputStream(socket.getOutputStream());
                System.out.println("get writer.");
                //ObjectInputStream is waiting for a header, we will be stuck until we completely receive it,
                //we should call flush() on the other side.
                reader = new ObjectInputStream(socket.getInputStream());
                System.out.println("get reader.");

socket = serverSocket.accept(); 这句话是阻塞语句,阻塞的意思是,在没有使用Socket进行连接时,程序会一直停留在这句话,知道出现了一个Socket进行连接,语句才能继续往下执行。

在客户端:

public class SocketClient extends Thread {

    private Scanner scanner;
    private Socket socket;
    private ObjectInputStream reader;
    private ObjectOutputStream writer;

    public SocketClient() throws IOException{
        scanner = new Scanner(System.in);
        socket = new Socket("10.30.131.230", 5555);
        System.out.println("A client has start.");
        reader = new ObjectInputStream(socket.getInputStream());
        writer = new ObjectOutputStream(socket.getOutputStream());
        writer.flush();
        System.out.println("reader writer.");

客户端只需要声明一个Socket对象,传入服务器的IP和端口就可以了,连接也随之建立。

使用输入流和输出流进行通信

服务器和客户端通信,需要ServerSocket和Socket使用相同的流进行交流。Java的API已经进行了封装,我们只需要简单的调用方法即可:

首先客户端Socket先得到自己的输入流和输出流:

public class SocketClient extends Thread {

    private Scanner scanner;
    private Socket socket;
    private ObjectInputStream reader;
    private ObjectOutputStream writer;

    public SocketClient() throws IOException{
        scanner = new Scanner(System.in);
        socket = new Socket("10.30.131.230", 5555);
        System.out.println("A client has start.");
        reader = new ObjectInputStream(socket.getInputStream());
        writer = new ObjectOutputStream(socket.getOutputStream());
        writer.flush();
        System.out.println("reader writer.");

代码相同, 这里我们看到通过

socket.getInputStream();
socket.getOutputStream();

可以得到客户端Socket自己的输入输出流,并且用ObjectStream进行了封装,之后客户端就可以使用这里的reader和writer对象,直接和ServerSocket使用自定义的对象进行交流。当然,用于通信的自定义对象需要进行序列化。

在服务端的代码如下:

                Message message = null;
                Socket socket;
                System.out.println("wait for a client.");
                socket = serverSocket.accept();
                System.out.println("accept a socket.");
                writer = new ObjectOutputStream(socket.getOutputStream());
                System.out.println("get writer.");
                //ObjectInputStream is waiting for a header, we will be stuck until we completely receive it,
                //we should call flush() on the other side.
                reader = new ObjectInputStream(socket.getInputStream());
                System.out.println("get reader.");

我们看到服务端这边也是通过先得到的socket,再调用socket方法的途径获得输入输出流的,不过这里我们还要注意在客户端,我们应该对得到的输出流调用flush()方法, 因为初次建立连接时,服务端这边对应的输入流会等待一个header,直到完全接收到,而flush()的作用就是将缓存中的内容全部写出。

使用心跳保持Socket连接

如果建立了Socket连接,也能通信了,别高兴的太早,如果一段时间不通信,Socket会自动断开连接,而解决的办法就是定期发送心跳,就是向服务器发送空消息,保持连接。

通常的办法是,写一个类,继承Thread,用来发送心跳,并且设置一个最大等待时间,如果到了最大等待时间,还没有向服务器发送消息或者接受到服务器的消息,那就向服务发送心跳。当然了,如果在这期间得到了反馈,就重置等待时间。

你可能感兴趣的:(Socket所遇到的坑)