服务器状态

一、服务器状态--繁忙

每个客户端都需要服务器进行双通等待

双通:客户端发送数据到服务器的接收通道

双通:服务器回送消息的发送通道

每条通道因为堵塞只能使用异步线程实现

二、服务器线程数量

一个客户端:双通->2条线程

n个客户端:2n条线程

服务器实际线程数量:2n+(服务器创建时的线程、垃圾回收的线程、监听客户端socket的线程、读取到内容后的转发线程)

三、服务器测试

想测试服务器,需要给服务器压力。服务器是进行客户端连接、发送、转发的地方。可以通过创建n个客户端,并且实时向客户端发送消息,然后测试服务器的压力状态。

四、测试代码

package net.qiujuer.lesson.sample.client;

import net.qiujuer.lesson.sample.client.bean.ServerInfo;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 这个测试类应该写什么东西呢?
 * 首先,需要测试服务器的性能,所以需要压力测试。需要进行构建非常多的客户端,并且连接到服务器端。
 * 然后使用客户端频繁地发送信息,测试服务器的压力状态。
 * 1、通过UDP拿到服务器信息
 * 2、开始循环建立1000个客户端,如果连接成功加到连接池
 * 3、当键盘输入任何内容后每隔1s对每个连接的客户端进行输出的操作
 * 4、当键盘再次输入任何内容后进行结束操作
 */
public class ClientTest {
    private static boolean done;
    public static void main(String[] args) throws IOException {
        ServerInfo info = UDPSearcher.searchServer(10000);
        System.out.println("Server:"+info);
        if(info == null){
            return;
        }

        //当前连接数量
        int size = 0;
        List<TCPClient> tcpClients = new ArrayList<>();
        for(int i=0;i<1000;i++){
            try{
                TCPClient tcpClient = TCPClient.startWith(info);
                if(tcpClient==null){
                    System.out.println("连接异常");
                }
                tcpClients.add(tcpClient);
                System.out.println("连接成功:"+(++size));
            }catch (IOException e){
                System.out.println("连接异常");
            }

            //当进行循环的时候,必须等待一点时间,因为服务器默认有阈值。当当前正在连接的客户端达到50以上,那么就会拒绝后面等待连接的客户端
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.in.read();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    while (!done){
                        for(TCPClient tcpClient:tcpClients){
                            tcpClient.send("Hello~~~");
                        }
                        try {
                            Thread.sleep(1000);
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
            };

            Thread thread = new Thread(runnable);
            thread.start();

            System.in.read();

            //等待线程完成
            done = true;
            try{
                thread.join();
            }catch (Exception e){
                e.printStackTrace();
            }

            //客户端结束操作
            for(TCPClient tcpClient : tcpClients){
                tcpClient.exit();
            }
        }
    }
}
package net.qiujuer.lesson.sample.client;


import net.qiujuer.lesson.sample.client.bean.ServerInfo;
import net.qiujuer.library.clink.utils.CloseUtils;

import java.io.*;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;

public class TCPClient {
    private final Socket socket;
    private final ReadHandler readHandler;
    private final PrintStream printStream;

    public TCPClient(Socket socket,ReadHandler readHandler) throws IOException {
        this.socket = socket;
        this.readHandler = readHandler;
        this.printStream = new PrintStream(socket.getOutputStream());
    }

    public void exit(){
        readHandler.exit();
        CloseUtils.close(printStream);
        CloseUtils.close(socket);
    }

    public void send(String msg){
        printStream.println(msg);
    }

    public static TCPClient startWith(ServerInfo info) throws IOException {
        Socket socket = new Socket();
        // 超时时间
        socket.setSoTimeout(3000);

        // 连接本地,端口2000;超时时间3000ms
        socket.connect(new InetSocketAddress(Inet4Address.getByName(info.getAddress()), info.getPort()), 3000);

        System.out.println("已发起服务器连接,并进入后续流程~");
        System.out.println("客户端信息:" + socket.getLocalAddress() + " P:" + socket.getLocalPort());
        System.out.println("服务器信息:" + socket.getInetAddress() + " P:" + socket.getPort());

        try {
            ReadHandler readHandler = new ReadHandler(socket.getInputStream());
            readHandler.start();

            return new TCPClient(socket,readHandler);
        } catch (Exception e) {
            System.out.println("连接异常");
            CloseUtils.close(socket);
        }

       return null;
    }



    static class ReadHandler extends Thread {
        private boolean done = false;
        private final InputStream inputStream;

        ReadHandler(InputStream inputStream) {
            this.inputStream = inputStream;
        }

        @Override
        public void run() {
            super.run();
            try {
                // 得到输入流,用于接收数据
                BufferedReader socketInput = new BufferedReader(new InputStreamReader(inputStream));

                do {
                    String str;
                    try {
                        // 客户端拿到一条数据
                        str = socketInput.readLine();
                    } catch (SocketTimeoutException e) {
                        continue;
                    }
                    if (str == null) {
                        System.out.println("连接已关闭,无法读取数据!");
                        break;
                    }
                    // 打印到屏幕
                    System.out.println(str);
                } while (!done);
            } catch (Exception e) {
                if (!done) {
                    System.out.println("连接异常断开:" + e.getMessage());
                }
            } finally {
                // 连接关闭
                CloseUtils.close(inputStream);
            }
        }

        void exit() {
            done = true;
            CloseUtils.close(inputStream);
        }
    }
}
发布了174 篇原创文章 · 获赞 115 · 访问量 83万+

猜你喜欢

转载自blog.csdn.net/nicolelili1/article/details/103982218