卷前:

  1. 首先得有IO的基本知识,然后了解下BIO、NIO、AIO;
  2. socket虽然用处很片面,不过它的TCP、UDP拓展思想还是值得去学习;
  3. 重点在于阻塞

问题:初学者在学习socket时,会发现serversocket.accept返回socket后(即客户端与服务端建立了连接),这里称为一个session,在每次收发数据时由于socket是bio模式,即阻塞型的流传输。


情境①:客户端socket.getOutputStream之后write和flush刷新发送流到服务端,服务端相应地serversocket.accept返回socket后socket.getInputStream后持续接收流,服务端想socket.getOutputStream发送流给客户端,客户端socket.getInputStream接收流。(基于TCP)

问题出现:服务端会由于接收流一直在进行,而导致之后的步骤是全部失效的!

解决办法

  1. 使用多线程,接收与发送用不同的线程;
  2. 使用包装流,如printWriter中的println方法一次发送“一行”流,再bufferedReader中readline方法一次读取“一行”流。

思考:如解决方法2所述,似乎是带入了文件末尾流概念,即流有结束标志?

答案如下,的确InputStream中read方法也有说明在读取到文件流末尾会返回-1

    1. Returns:the next byte of data, or

-1

    if the end of the stream is reached.

但是问题在于socket阻塞的深度意思是这个-1根本不存在,于是也合理的解释了

而printWriter中的println方法

Terminates the current line by writing the line separator string. The line separator string is defined by the system property line.separator, and is not necessarily a single newline character ('\n').

bufferedReader中readline方法

Reads a line of text. A line is considered to be terminated by any one of a line feed (‘\n’), a carriage return (‘\r’), or a carriage return followed immediately by a linefeed.

Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached

由于存在换行符,流管道一直存在,但是双方默契地使用\n来作为阻塞打破。


情境②:客户端单线程or多线程方式发送流,服务端多线程方式接收流,服务端相应流并返回流,客户端接收到服务端响应流。(基于TCP)

问题:多线程的开启与处理方式!

服务端

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

/**
 * 大二16年下半年写的套接字程序,基于TCP协议的socket通信
 * 修改2018-4-9
 * 修改2018-6-
 * 多线程
 * @author pcshao
 */
public class serverT {
  
  private static ArrayList<Socket> sockets = new ArrayList<Socket>();
  private static ServerSocket cServer = null;
  private static int ADDRESS_PORT = 61234;
  
  private static void transmitMessage(Socket socket){
    new Thread(new Thread()){
      public void run(){
        try {
          while(true) {
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String text = br.readLine();
            System.out.print("接收成功,准备向客户端发送\n");
            System.out.println(text);
//						socket.shutdownInput();
            //多客户端同步消息
            for(Socket s:sockets) {
              PrintWriter pw = new PrintWriter(s.getOutputStream());
              pw.println(s.getInetAddress()+":"+text);
              pw.flush();
            }
          }
        } catch (IOException e) {
          System.out.println("客户端发送丢失");
        }
    }}.start();
  }

  public static void main(String[] args){
    try {
      cServer = new ServerSocket(ADDRESS_PORT);
    } catch (IOException e) {
      System.out.println("聊天服务开启失败");
    }
    System.out.println("服务器开启..");
    while(true){
      //accept侦听,socket实例
      Socket socket = null;
      try {
        socket = cServer.accept();
      } catch (IOException e) {
        e.printStackTrace();
      }
      //输出客户端IP
      System.out.println(socket.getInetAddress()+"\t已连接");
      //接收到的每一个客户端socket存到链表里
      sockets.add(socket);
      //转换信息
      transmitMessage(socket);
    }
  }
}

 

 

客户端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Client_dual {

  public static Socket socket;
  private static String ADDRESS_URL = "127.0.0.1";
  private static int ADDRESS_PORT = 61234;
  //socket创建
  private static boolean createSocket() {
    try {
      socket = new Socket(ADDRESS_URL,ADDRESS_PORT);
      return true;
    } catch (IOException e) {
      System.out.println("连接失败,请检查服务端");
      return false;
    }
  }
  //接收线程
  public void receive(Socket socket) {
    new Thread(new Thread()) {
      public void run() {
        while(true) {
          try {
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String text = "";
            if((text = br.readLine())!="")
              System.out.println(text);
          } catch (IOException e) {
            e.printStackTrace();
          }
        }
      }
    }.start();
  }
  //发送线程
  public void send(Socket socket) {
    new Thread(new Thread()) {
      public void run() {
        while(true) {
          try {
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
            String text = new Scanner(System.in).nextLine();
            pw.println(text);
            pw.flush();
          }catch(IOException e) {
            e.printStackTrace();
          }
        }
      }
    }.start();
  }
  public static void main(String[] args) {
    Client_dual c = new Client_dual();
    if(!createSocket())
      System.out.println("创建失败");
    c.receive(socket);
    c.send(socket);
  }
}

 

卷后:

  1. 更新;

未经授权,禁止转载。