Java面试知识点(七十)Socket编程——C/S架构基础入门

Java面试知识点(七十)Socket编程——C/S架构基础入门_第1张图片

通信双方一方作为服务器等待客户提出请求并予以响应。客户则在需要服务时向服务器提 出申请。服务器一般作为守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客户,同时自己继续监听服务端口,使后来的客户也 能及时得到服务。

单线程客户端和服务器通信

【服务器】

package test.socket;

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

public class TestServer {
    public static void main(String[] args) {
        try {
            // 服务器socket并指定端口
            ServerSocket server = new ServerSocket(9999);
            // 接收服务器
            Socket socket = server.accept();
            // 获取服务器的输入流
            BufferedReader reader
                    = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            // 获取服务器的输出流
            PrintWriter writer = new PrintWriter(socket.getOutputStream(),true);

            // 来自键盘的输入数据
            BufferedReader keyword =
                    new BufferedReader(new InputStreamReader(System.in));

            while (true) {
                // 当有输入数据的时候,ready返回true
                if (reader.ready()) {
                    String str = reader.readLine();
                    System.out.println("Client: "+str);
                }
                // 捕获服务器另一个输入流,有数据,发送给client并打印
                if (keyword.ready()) {
                    String keyStr = keyword.readLine();
                    writer.println(keyStr);
                    System.out.println("Server: " + keyStr);
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

【客户端】

package test.socket;

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

public class TestClient {
    public static void main(String[] args) {

        try {
            // 连接指定的服务器socket
            Socket socket = new Socket("localhost",9999);

            // 输入流
            BufferedReader reader =
                    new BufferedReader(new InputStreamReader(socket.getInputStream()));

            // 输出流
            PrintWriter writer =
                    new PrintWriter(socket.getOutputStream(), true);

            // 键盘输入
            BufferedReader keyword =
                    new BufferedReader(new InputStreamReader(System.in));

            while (true) {
                if (reader.ready()) {
                    String str = reader.readLine();
                    System.out.println("Server:" + str);
                }
                if (keyword.ready()) {
                    String key = keyword.readLine();
                    writer.println(key);
                    System.out.println("Client:" + key);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

【运行结果】
Java面试知识点(七十)Socket编程——C/S架构基础入门_第2张图片Java面试知识点(七十)Socket编程——C/S架构基础入门_第3张图片


多线程客户端和服务器通信

上一个例子,只能支持单一客户端和服务器通信,如果想要多个客户端与服务器保持通讯,则需要引入多线程

一个socket只能连接一个客户端和一个服务器,如果想要多个客户端与服务器通讯就需要多线程,这里多线程指的是,服务器方面每接收一个客户端的请求,就起一个子线程,具体操作就是serversocket.accept()方法作为子线程的参数传入,这样就实现多个客户端同时与服务器

实现runnable接口的服务器线程类

package test.socket.practice1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class SingleServer implements Runnable{
    private Socket socket;

    public SingleServer(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            boolean flag = true;
            // 保证可以循环输入数据
            while (flag) {
                // 读取从客户端的信息
                read();

                // 读取从键盘的信息
                BufferedReader keyword =
                        new BufferedReader(new InputStreamReader(System.in));
                if (keyword.ready()) {
                    String keyStr = keyword.readLine();
                    System.out.println("服务器: "+keyStr);
                    write(keyStr);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 在服务器读取客户端发送过来的信息
     * */
    private void read() {
        try {
            BufferedReader reader =
                    new BufferedReader(new InputStreamReader(socket.getInputStream()));
            if (reader.ready()) {
                String readStr = reader.readLine();
                System.out.println("客户端" + readStr);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 把服务器写的信息发送给客户端
     * */
    private void write(String str) {
        try {
            PrintWriter writer =
                    new PrintWriter(socket.getOutputStream(),true);
            writer.println("服务器:"+str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务器类,开启线程,循环侦听客户端,每当一个客户端请求之后,就会启动一个线程与客户端相连

package test.socket.practice1;

import test.test.thread1;

import java.io.IOException;
import java.net.ServerSocket;

public class Server {
    public static void main(String[] args) {
        try {
            // 设定监控端口,客户端可以寻找到
            ServerSocket server = new ServerSocket(9999);
            System.out.println("服务器开启...");
            // 循环侦听客户端请求
            while (true) {
                SingleServer singleServer = new SingleServer(server.accept());
                Thread t = new Thread(singleServer);
                // 开启多线程
                t.start();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

单线程客户端,可以多次启动(在idea中,默认是不能同时运行同一个类的,需要点击设置在这里插入图片描述
Java面试知识点(七十)Socket编程——C/S架构基础入门_第4张图片勾中选择框)

package test.socket.practice1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class SingleClient {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 声明socket,并设定连接的服务器
                    Socket socket = new Socket("localhost",9999);
                    System.out.println("客户端开启...");

                    // 声明输入输出流
                    BufferedReader reader =
                            new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    BufferedReader key =
                            new BufferedReader(new InputStreamReader(System.in));
                    PrintWriter writer =
                            new PrintWriter(socket.getOutputStream(),true);

                    boolean flag = true;
                    while (flag) {
                        if (reader.ready()) {
                            String str = reader.readLine();
                            System.out.println("服务器:"+str);
                        }
                        if (key.ready()) {
                            String strKey = key.readLine();
                            writer.println(Thread.currentThread().getName() +": "+ strKey);
                            System.out.println("客户端" + Thread.currentThread().getName() +": "+ strKey);
                            // 客户端退出
                            if ("exit".equals(strKey)) {
                                flag = false;
                                socket.close();
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

先启动server,在启动多个SingleClient ,可以实现多个客户端与server通讯
Java面试知识点(七十)Socket编程——C/S架构基础入门_第5张图片

Java面试知识点(七十)Socket编程——C/S架构基础入门_第6张图片

Java面试知识点(七十)Socket编程——C/S架构基础入门_第7张图片

关于多线程socket编程,这里是有很多内容的,上面的这个只是一个简单的demo,还有很多问题,比如说,多个客户端的信息都可以发送到服务器,但是服务器是无法发送给客户端的,因为socket都在连接着,服务器只发送一个,不知道发给谁(也就说,服务器开启了多线程,但是从客户端看来,依旧只有一个服务器跟自己相连,服务器发送的消息,当只有一个客户端的时候是可以接收到的吗,但是多个客户端就不行。),其次,还有一种场景,服务器作为中间纽带,多客户之间互相通信(也就是聊天室类似的功能),我会一一补充

补充
Java面试知识点(七十一)Socket编程——多线客户端和服务器通讯

你可能感兴趣的:(Java面试知识汇总,java,面试)