本文记录使用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会自动断开连接,而解决的办法就是定期发送心跳,就是向服务器发送空消息,保持连接。
通常的办法是,写一个类,继承Thread,用来发送心跳,并且设置一个最大等待时间,如果到了最大等待时间,还没有向服务器发送消息或者接受到服务器的消息,那就向服务发送心跳。当然了,如果在这期间得到了反馈,就重置等待时间。