要求从浏览器访问服务器

并立即让服务器响应一个很简单的网页给浏览器显示

网页的内容是:“我爱你,中国。”

BS架构的基本原理:

浏览器通过URL统一资源定位符,地址:http://服务器IP:服务器端口找到服务器程序,与服务器建立一个通信管理,响应浏览器请求的数据。

BS架构的基本原理:

注意:服务器必须给浏览器响应HTTP协议规定的数据格式,否则浏览器不识别返回的数据。

HTTP协议规定:响应给浏览器的数据格式必须满足如下格式:

  

代码:

Server:

package cn.chang.d8_tcp5;

import java.net.ServerSocket;
import java.net.Socket;

/**
 * 目标:完成TCP通信快速入门—服务端开发,要求实现与多个客户端同时通信
 */
public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("===服务端启动成功===");
        // 1. 创建ServerSocket的对象,同时为服务端注册端口,方便客户端程序找到它
        ServerSocket serverSocket = new ServerSocket(8080);

        while (true) {
            // 2. 需要使用serverSocket对象调用accept方法等待客户端的连接请求
            Socket socket = serverSocket.accept();     // 端到端的通信管道

            System.out.println("有人上线了!" + socket.getRemoteSocketAddress());

            // 3. 把这个客户端对应的socket通信管道交给一个独立的线程负责处理。
            new ServerReaderThread(socket).start();
        }
    }
}

 

ServerReaderThread:

package cn.chang.d8_tcp5;

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

public class ServerReaderThread extends Thread{

    private Socket socket;              //  成员变量socket
    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        // 响应一个网页内容,“我爱你,中国”给浏览器显示
        try {
            OutputStream os = socket.getOutputStream();

            PrintStream ps = new PrintStream(os);

            ps.println("HTTP/1.1 200 OK");
            ps.println("Content-Type: text/html; charset=utf-8");
            ps.println();
            ps.println("<div style='color:red;font-size:14px;text-align:center;'>我爱你,中国</div>");

            ps.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

启动服务器,然后使用浏览器进行访问:

扩展知识:

每次请求都开一个新线程,到底好不好?

高并发的时候,容易死机。

10万个并发,那就产生10万个线程,线程是占用资源的,那么就容易宕机。

我们可以使用线程池进行优化。

复用线程,让线程可以处理另外一个管道的任务。

固定了线程池的线程和任务数量。

代码:

Server类:

package cn.chang.d9_tcp6;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;

/**
 * 目标:完成TCP通信快速入门—服务端开发,要求实现与多个客户端同时通信
 */
public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("===服务端启动成功===");
        // 1. 创建ServerSocket的对象,同时为服务端注册端口,方便客户端程序找到它
        ServerSocket serverSocket = new ServerSocket(8080);

        // 创建出一个线程池,负责处理通信管道的任务
        ThreadPoolExecutor pool = new ThreadPoolExecutor(32, 32, 0,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(8),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());


        while (true) {
            // 2. 需要使用serverSocket对象调用accept方法等待客户端的连接请求
            Socket socket = serverSocket.accept();     // 端到端的通信管道
            
            // 3. 把这个客户端对应的socket通信管道交给一个独立的线程负责处理。
            pool.execute(new ServerReaderRunnable(socket));
        }
    }
}

ServerReaderRunnable类:

package cn.chang.d9_tcp6;

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;

public class ServerReaderRunnable implements Runnable {

    private Socket socket;              //  成员变量socket
    public ServerReaderRunnable(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        // 响应一个网页内容,“我爱你,中国”给浏览器显示
        try {
            OutputStream os = socket.getOutputStream();

            PrintStream ps = new PrintStream(os);

            ps.println("HTTP/1.1 200 OK");
            ps.println("Content-Type: text/html; charset=utf-8");
            ps.println();
            ps.println("<div style='color:red;font-size:14px;text-align:center;'>我爱你,中国</div>");

            ps.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

执行结果:

可以反复把网络通信这部分内容好好练习练习,消化一下。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐