服务器:

1.与客户端的交流手段多是I/O流的方式

2.对接的方式是Socket套接字,套接字通过IP地址和端口号来建立连接

3.(曾经十分影响理解的点)服务器发出的输出流的所有信息都会成为客户端的输入流,同时所有客户端的所有输出流都会包含在服务器的输入流中。

(即套接字即使建立连接,输入输出流都是相对自己的而言的,向外发送自己的内部的信息都用输出流,接受外部的数据都使用输入流!)

简单服务器的代码实现:

public static void main(String [] args){
  try {
  //建立本地服务端,并监听6788端口号
     ServerSocket server = new ServerSocket(6788);
   //获取键盘输入,作为服务器向客户端发送的信息
    Scanner reader = new Scanner(System.in);
      while (true) {
        Socket c = server.accept();
         BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
         BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(c.getOutputStream()));
         String line;
         if ((line=br.readLine())!=null) {
           System.out.println(line);
         }
         if ((line=reader.nextLine())!=null) {
           bw.write(line);
            bw.newLine();//由于判断的时候都是nextline(),所以每次输入都必须自己给出一个换行
            bw.flush();
         }
      }

   } catch (IOException e) {
            // TODO Auto-generated catch block
        e.printStackTrace();
   }
}

与服务器链接并实现交流的客户端代码实现:

public static void main(String[] args) {
        try {
      //连接到本地主机的6788端口(127.0.0.1为本地主机IP)
            Socket c = new Socket("127.0.0.1",6788);
            //获取键盘输入信息,做为向服务器发送的信息
            Scanner reader = new Scanner(System.in);
            
            BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(c.getOutputStream()));
            String line;
            while(true){
                if ((line = reader.nextLine())!=null) {
                    bw.write(line);
                    bw.newLine();  //客户端和服务器的读取操作都是行,所以需要自己给出换行,避免出错
                    bw.flush();
                }
                if ((line=br.readLine())!=null) {
                    System.out.println(line);
                }
            }        
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

 

一般服务器绝不可能只为一个客户端服务,当存在很多客户端的时候,需要为每个客户端的链接建立独立的线程,使得客户端之间不会干扰,独立运行。

线程的控制实现方法有两种:

1.自定义线程类继承Thread,并重现run()方法;

2.自定义一个普通类,实现Runnable接口(本文采用此方法实现多线程控制)

具体代码实现:

//服务器的代码
public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(6666);
            
            while (true) {
          //一直监控是否有客户端连接
                Socket s = serverSocket.accept();
                //每当有客户端连接时,为每个客户端开辟独立线程执行
                Thread ch = new Thread(new ThreadManager(s));
                ch.start();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

实现线程的自定义类:

public class ThreadManager implements Runnable{

    private Socket socket;
    
    public ThreadManager(Socket s){
        this.socket = s;
    }
    @Override
    public void run() {
        BufferedWriter bw;
        BufferedReader br;
        try {
            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
           //连续不断地向客户端发送信号,数字不断在变化,若客户端先后链接,发送的信息独立则独立线程实现 
       for(int i = 0; i<1000000;i++){
        bw.write(i+"````````````````");
        bw.newline();
        bw.flush();
        }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
    }
}

用来接收服务端的客户端代码实现:

public static void main(String[] args) {
        try {
        //链接到本地的6666端口
            Socket s = new Socket("127.0.0.1",6666 );
            
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            String line;
        while(true){
            while ((line = br.readLine())!=null) {
                //将服务器发送的信息输出
          System.out.println(line);
            }
        }
    
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }    
    }

注:为方便观察,可在cmd窗口中启动客户端的代码,重复打开几个dos窗口,并链接到本地的6666端口,就会收到服务器发送过来的递增的数字,所有的dos窗口都启动后,可以发现每个窗口的数字增长的程度并不相同,但都一直在运行,互不干扰,至此,为客户端创立的独立线程实现。