互联网编程之多线程/线程池TCP服务器端程序设计

这篇具有很好参考价值的文章主要介绍了互联网编程之多线程/线程池TCP服务器端程序设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

需求

多线程TCP服务器

线程池TCP服务器

测试

日志模块


需求

多线程TCP服务器(30分):

设计编写一个TCP服务器端程序,需使用多线程处理客户端的连接请求。客户端与服务器端之间的通信内容,以及服务器端的处理功能等可自由设计拓展,无特别限制和要求。

线程池TCP服务器(30分):

设计编写一个TCP服务器端程序,需使用线程池处理客户端的连接请求。客户端与服务器端之间的通信内容,以及服务器端的处理功能等可自由设计拓展,无特别限制和要求,但应与第1项要求中的服务器功能一致,便于对比分析。

比较分析不同编程技术对服务器性能的影响(20分):

自由编写客户端程序和设计测试方式,对1和2中的服务器端程序进行测试,分析比较两个服务器的并发处理能力。

设计编写可重用的服务器日志程序模块,日志记录的内容和日志存储方式可自定(比如可以记录客户端的连接时间、客户端IP等,日志存储为.TXT或.log文件等),分别在1和2的服务器程序中调用该日志程序模块,使多线程TCP服务器和线程池TCP服务器都具备日志功能,注意线程之间的同步操作处理。(20分)

多线程TCP服务器

这段代码是一个基于Java的多线程服务器实现,用于接收客户端的连接并处理其发送的消息。

  1. 首先,在MultithreadingServer类的main方法中:

    • 创建了一个ServerSocket对象,并指定它监听的端口号为8888,同时设置最大连接数量为10000。
    • 进入一个无限循环,用于持续接受客户端的连接请求。
    • 每次循环,当有客户端连接时,创建一个新的MultiThread实例,并传入对应的Socket对象。
    • 同时,创建一个Logger实例,记录连接的相关信息,包括客户端的IP地址、连接时间和日志文件名。
  2. MultiThread类中:

    • 继承了Thread类,并重写了run方法。
    • run方法中,通过BufferedReaderSocket的输入流获取一个字符输入流,并通过InputStreamReader将其转换为字符流,然后读取客户端发送的数据。
    • 使用一个循环来连续读取,直到达到输入流的末尾(客户端关闭连接)为止。
    • 在每次循环中,打印接收到的消息到标准输出。
    • 最后,关闭输入流和Socket连接。

整体而言,这段代码实现了一个简单的多线程服务器,能够接收并处理客户端的连接请求,以及读取和输出客户端发送的消息。日志记录部分使用了自定义的Logger类,但其具体实现不在这段代码中显示。需要注意的是,异常处理方面可能需要根据实际需求进行补充和调整。

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

public class MultithreadingServer {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8888, 10000);
            while (true) {
                Socket client = serverSocket.accept();
                new MultiThread(client).start();
                new Logger(client.getInetAddress().getHostAddress(), new Date(), "LogMultithreadingServer.txt");
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

class MultiThread extends Thread {
    private Socket socket = null;

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

    public void run() {
        try {
            BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String message = null;
            while ((message = input.readLine()) != null) {
                System.out.println(message);
            }
            input.close();
            socket.close();
        } catch (IOException error) {
            error.printStackTrace();
        }
    }
}

线程池TCP服务器

这段代码是一个使用线程池的多线程服务器实现,与前面的代码相比,在并发处理客户端连接方面进行了改进。

  1. ThreadPoolServer类的main方法中:

    • 创建了一个具有200个线程的固定大小线程池ExecutorService
    • 创建了一个ServerSocket对象,并指定它监听的端口号为9999,同时设置最大连接数量为10000。
    • 进入一个无限循环,用于持续接受客户端的连接请求。
    • 每次循环,当有客户端连接时,将一个新的TheadPoolTask任务提交给线程池进行执行。
    • 同时,创建一个Logger实例,记录连接的相关信息,包括客户端的IP地址、连接时间和日志文件名。
  2. TheadPoolTask类中:

    • 实现了Runnable接口,并重写了run方法。
    • run方法中,通过BufferedReaderSocket的输入流获取一个字符输入流,并通过InputStreamReader将其转换为字符流,然后读取客户端发送的数据。
    • 使用一个循环来连续读取,直到达到输入流的末尾(客户端关闭连接)为止。
    • 在每次循环中,打印接收到的消息到标准输出。
    • 最后,关闭输入流和Socket连接。

整体而言,这段代码与前一段代码类似,不同之处在于使用了线程池来管理线程资源,提高了并发处理能力。通过将任务提交给线程池执行,可以控制并发线程数,并重复利用线程,避免频繁创建和销毁线程带来的开销。需要注意的是,异常处理方面可能需要根据实际需求进行补充和调整。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolServer {
    public static void main(String[] args) {
        ExecutorService executorService= Executors.newFixedThreadPool(200);
        try{
            ServerSocket serverSocket=new ServerSocket(9999,10000);
            while(true){
                Socket client=serverSocket.accept();
                executorService.execute(new TheadPoolTask(client));
                new Logger(client.getInetAddress().getHostAddress(),new Date(),"LogThreadPoolServer.txt");
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            executorService.shutdown();
        }
    }
}
class TheadPoolTask implements Runnable{
    private Socket socket=null;
    public TheadPoolTask(Socket socket){
        this.socket=socket;
    }
    public void run(){
        try{
            BufferedReader input=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String message=null;
            while((message=input.readLine())!=null){
                System.out.println(message);
            }
            input.close();
            socket.close();

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

测试

编写一个压力测试程序,测试多线程服务器和线程池服务器在高并发时的表现,实现run()方法,发起连接请求,为了保证多线程并发访问long类型变量时的线程安全性,使用线程安全的AtomicLong类来记录服务器响应的时间,如图7所示,附件已含源代码。

互联网编程之多线程/线程池TCP服务器端程序设计,互联网编程,tcp/ip,服务器,网络

图7

主程序同时向两个服务器发起多个连接,连接规模从1000个连接请求开始一直增加到10000个,通过在短时间内发起大量连接请求来对服务器进行压力测试,如图8所示。

互联网编程之多线程/线程池TCP服务器端程序设计,互联网编程,tcp/ip,服务器,网络

图8

测试过程数据如图9所示。

互联网编程之多线程/线程池TCP服务器端程序设计,互联网编程,tcp/ip,服务器,网络

图9

分析两个服务器的表现情况,如图10所示,可见在处理大量短任务(如处理网络请求)的情况下,使用线程池可以避免频繁地创建、销毁线程所带来的开销,因此会更快一些。

互联网编程之多线程/线程池TCP服务器端程序设计,互联网编程,tcp/ip,服务器,网络

图10

这段代码是一个简单的测试服务器和客户端的程序。

  1. TestServerClient类的main方法中:

    • 通过循环来控制不同规模(power)的测试。
    • 在每个测试规模下,通过嵌套循环启动一定数量(2000)的测试任务。
    • 每个测试任务使用TestTask类创建一个线程,构造函数传入不同的端口号(9999或8888),然后调用run方法运行测试任务。
    • 在每次测试任务完成后,将消耗的时间输出到控制台。
  2. TestTask类中:

    • 定义了一个port变量,表示客户端连接的目标端口。
    • 声明了两个静态的AtomicLong对象timePooltimeMulti,用于记录线程池和多线程方式的测试消耗时间。
    • 在构造函数中接收一个端口号,并将其赋值给port变量。
    • run方法实现了客户端的测试逻辑:
      • 创建一个空的Socket对象。
      • 构建InetSocketAddress对象,指定本地主机地址和目标端口。
      • 记录当前时间为起始时间。
      • 调用socket.connect方法与服务器建立连接,等待连接完成。
      • 关闭socket对象。
      • 记录当前时间为结束时间。
      • 根据不同的端口号,将测试消耗时间累加到相应的AtomicLong对象中。

该程序的主要目的是通过多次连接服务器的测试来比较线程池和多线程方式的性能消耗。它会启动一定数量的测试任务,并分别记录两种方式的测试消耗时间。在每次测试任务完成后,将消耗时间输出到控制台。通过对不同规模测试结果的比较,可以初步评估线程池和多线程方式的性能表现。

import java.io.IOException;
import java.net.*;
import java.util.concurrent.atomic.AtomicLong;

public class TestServerClient {
    public static void main(String[] args) {
        for (int power = 1; power <= 10; power++) {
            int scale = 2000*power ;
            for (int i = 0; i < 2000; i++) {
                if(i%2==0)
                new TestTask(9999).run();
                else new TestTask(8888).run();
            }
            System.out.printf("线程池:规模为%d消耗时间%d毫秒\n", scale/2, TestTask.timePool.get());
            System.out.printf("多线程:规模为%d消耗时间%d毫秒\n", scale/2, TestTask.timeMulti.get());
        }
    }
}

class TestTask{
    private final int port;
    public static AtomicLong timePool =new AtomicLong();
    public static AtomicLong timeMulti=new AtomicLong();

    public TestTask(int port) {
        this.port = port;
    }

    public void run() {
        try {
            Socket socket = new Socket();
            SocketAddress socketAddress=new InetSocketAddress(InetAddress.getLocalHost(), port);
            long start=System.currentTimeMillis();
            socket.connect(socketAddress);
            while(!socket.isConnected()){}
            socket.close();
            long end=System.currentTimeMillis();
            if(port==9999)
            timePool.addAndGet(end-start);
            else timeMulti.addAndGet(end-start);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }
}

日志模块

这段代码是一个简单的日志记录器类。它具有以下功能:

  1. 构造函数:接受一个IP地址、日期和文件路径作为参数,并生成一条以IP地址和日期为内容的日志信息。

  2. keep() 方法:该方法使用了 synchronized 关键字,以确保在多线程环境下只有一个线程可以访问该方法。在方法内部,它创建一个 BufferedWriter 对象,并将日志内容写入指定的文件中。

总体来说,这个代码实现了一个基本的日志记录功能,将用户登录的 IP 地址和日期写入指定的文件中。文章来源地址https://www.toymoban.com/news/detail-515844.html

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;

public class Logger {
    private final String log;
    private final String filePath;
    public Logger(String IP, Date date,String filePath){
        log=IP+" login at "+date.toString()+'\n';
        this.filePath=filePath;
        keep();
    }
    private synchronized void keep(){
        try {
            BufferedWriter bufferedWriter=new BufferedWriter(new FileWriter(filePath,true));
            bufferedWriter.write(log);
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

到了这里,关于互联网编程之多线程/线程池TCP服务器端程序设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Windows配置互联网访问检测服务器-IspSrv

    赛题 1、搭建服务 2、配置服务 3、配置IIS 4、客户端        原理 (一)服务器 IspSrv 上的工作任务 1.互联网访问检测服务器  为了模拟 Internet 访问测试,请搭建网卡互联网检测服务。

    2024年02月13日
    浏览(51)
  • 宝塔面板搭建Discuz论坛并发布互联网访问【无需云服务器】

    ✨个人主页:bit me👇 转载自cpolar极点云的文章:Linux宝塔面板搭建Discuz论坛,并公网远程访问【内网穿透】 Crossday Discuz! Board(以下简称 Discuz!)是一套通用的社区论坛软件系统,用户可以在不需要任何编程的基础上,通过简单的设置和安装,在互联网上搭建起具备完善功能

    2024年02月03日
    浏览(65)
  • 分享本周所学——在Windows上搭建自己的Git服务器并支持互联网远程访问

            大家好,欢迎来到《分享本周所学》第十期。本人是一名人工智能初学者(虽然我最近写的东西都跟人工智能没什么关系),刚刚上完大一。之前想跟同学搞项目,我的学校自己有一个GitLab服务器,于是就把项目存在上面,但是后来收到学校邮件说学校服务器不允

    2024年02月09日
    浏览(51)
  • 网络互联与互联网 - TCP 协议详解

    在 TCP/IP 协议簇 中有两个传输协议 TCP :Transmission Control Protocol, 传输控制协议 ,是面向 连接 的、可靠的。 UDP :User Datagram Protocol, 用户数据报协议 ,是面向 无连接 的、不可靠的。 参数 英文名 说明 源端口 Sorce Port 目的端口 Destination Port 序号 Sequence Number 保证数据的可靠

    2024年02月11日
    浏览(57)
  • 《互联网的世界》第三讲-tcp

    dns 找到了地址,spf 确定了路径,如何运输数据呢?今天讲 tcp。 计算机网络领域的特定技术是最后当你干这个事时才要用的,我对孩子们这样说,实际上你可以随便看一个快递单子来理解端到端传输协议。 源地址,目标地址一定要有,一个地址可能有不同住户,也就是 por

    2024年03月10日
    浏览(90)
  • 从 TCP/IP 到 CCIP:Chainlink 与合约的互联网

    未来已来。通过链上金融重塑资本市场预计将影响全球价值 8.67 万亿美元的资产的使用方式。 Chainlink 的跨链互操作性协议(CCIP)将会这一转型过程中发挥重要作用,这是区块链连接性和互操作性的突破,使得 DeFi 应用可以通过单一界面访问用户,并与其他不同区块链上的

    2024年02月14日
    浏览(41)
  • 互联网基石:TCP/IP 四层模型,由浅入深直击原理!

    TCP/IP 是迄今为止最常用的网络互联协议套件,在全球互联网运营方面发挥了巨大作用,可以这样说 TCP/IP 在互联网世界无处不在! TCP/IP 最初由 DARPA(美国国防高级研究计划局)的两位科学家于 1970 年代开发,这两位科学家分为是 Vint Cerf 和 Bob Kahn,被称为 Internet 之父 。 当时

    2024年02月04日
    浏览(44)
  • 互联网编程之域名IP转换及应用URL类定位和获取数据编程

    目录 需求 域名解析程序 下载功能程序 断点续传下载 编写域名解析程序(30分): 编写一个可重用的域名解析程序模块,使之能够将用户输入的域名解析为IP地址。 编写下载功能程序(40分): 使用URL类,编写一个可重用的下载程序模块,完成HTML和图像文件的下载。即用户

    2024年02月12日
    浏览(83)
  • 互联网Java工程师面试题·Java 并发编程篇·第五弹

    目录 52、什么是线程池? 为什么要使用它? 53、怎么检测一个线程是否拥有锁? 54、你如何在 Java 中获取线程堆栈? 55、JVM 中哪个参数是用来控制线程的栈堆栈小的? 56、Thread 类中的 yield 方法有什么作用? 57、Java 中 ConcurrentHashMap 的并发度是什么? 58、Java 中 Semaphore 是什么

    2024年02月07日
    浏览(67)
  • 书栈网-BookStack 程序员IT互联网开源编程书籍免费阅读

    书栈网是一个提供各种编程语言和技术的开源书籍免费阅读的网站,涵盖前端、后端、数据库、算法、数据分析等领域。您可以在书栈网找到最新最热的开源书籍,以及相关的文档资料。 书栈网提供网页版跟手机APP。 网页版书栈网官网地址:https://www.bookstack.cn/ 手机版 Book

    2024年02月04日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包