TCP的socket API

news2024/9/25 11:14:54

1、核心类

ServerSocket :服务器使用的socket

Socket : 服务器和客户端都会使用的socket

accept进行的工作是拉客

对应操作系统来说,建立TCP连接是内核的工作

accept要干的就是等连接建立好了,把这个连接给拿到应用程序中。

如果当前连接还没建立,accept就会阻塞,accept相当于,有人给你打电话了,你按下接听键!如果没人打电话,就阻塞等待。

一、回显服务器

 1、服务器

注:

1、代码中,使用了 clientSocket 用完之后,需要关闭。

和代码中 ServerSocket 生命周期不一样,ServerSocket的生命周期跟随整个程序, clientSocket生命周期,只是当前连接。就应该在连接之后,把这里的 socket 关闭,不关就会造成资源泄露。ServerSocket只有一个,clientSocket 会有无数个,每个客户端的连接,都是一个。

2、利用多线程,来实现多个客户端同时运行

一个线程调用一个processConnect。

3、通过线程池,来解决频繁创建销毁线程的问题

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {
    private ServerSocket serverSocket = null;
    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动!");
        //创建线程池
        ExecutorService service = Executors.newCachedThreadPool();
        while (true){
            Socket clientSocket = serverSocket.accept();

            //[版本1] 单线程版本,存在bug,无法处理多个客户端
            //不是直接调用,而是创建一个新的线程,让新的线程来调用。
            //processConnect(clientSocket);

            //[版本2] 多线程版本,主线程负责拉客,新线程负责通信
            //虽然比版本1有提升,但是涉及到频繁创建销毁线程,在高并发的情况下,负担是比较重的
//            Thread T = new Thread(() -> {
//                try {
//                    processConnect(clientSocket);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            });
//            T.start();

            //[版本3] 使用线程池,来解决频繁创建销毁线程的问题
            service.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        processConnect(clientSocket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    //通过这个方法,给当前连上的这个客户端,提供服务
    //一个连接过来了,服务方式可能有两种:
    //1、一个连接只进行一次数据交互(一个请求+一个响应) 短连接
    //2、一个连接进行多次数据交互(N个请求 + N个响应)  长连接
    //此处写长连接的版本,短连接就是长连接去掉while循环
    public void processConnect(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 建立连接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()){
            Scanner scanner = new Scanner(inputStream);
            PrintWriter printWriter = new PrintWriter(outputStream);
            //这里是长连接的写法,需要while来获取多次交互情况
            while (true){
                if(!scanner.hasNext()){
                    //读完了,就断开连接。即当客户端断开连接的时候,此时 hasnext 就会返回 false
                    //读到EOF的时候(end of file)返回false,当客户端进程退出的时候,也就会触发socket文件关闭,此时服务器这边尝试读取请求,就会读到EOF
                    System.out.printf("[%s:%d] 断开连接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
                   break;
                }
                //1、读取请求并解析
                String request = scanner.next();
                //2、根据请求计算响应
                String response = process(request);
                //3、把响应写回给客户端
                printWriter.println(response);
                //4、刷新一下缓冲区,避免数据没有真的发出去
                printWriter.flush();
                System.out.printf("[%s:%d] req:%s;resp:%s\n",
                        clientSocket.getInetAddress().toString(),clientSocket.getPort(),
                        request,response);
            }
        }finally {
            clientSocket.close();
        }
    }
    public String process(String req){
        return req;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer echoServer = new TcpEchoServer(8000);
        echoServer.start();
    }
}

2、客户端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoClient {
   private Socket socket = null;
   public TcpEchoClient() throws IOException {
      //new这个对象的时候,需要和服务器建立连接 建立连接,就得知道,服务器在哪里
      //new Socket的过程就是建立连接的过程
      socket = new Socket("127.0.0.1",8000);
   }
   public  void start() throws IOException {
      //由于实现的是长连接,一个连接会处理 N 个请求和响应,需要加上while循环
      //从键盘输入
      Scanner scanner = new Scanner(System.in);
      try(InputStream inputStream = socket.getInputStream();
          OutputStream outputStream = socket.getOutputStream()) {
         //从网络上输入
         Scanner scannerNet = new Scanner(inputStream);
         PrintWriter printWriter = new PrintWriter(outputStream);
         while(true){
            //1、从控制台读取用户输入
            System.out.print("> ");
            String request = scanner.next();
            //2、把请求发送给服务器
            printWriter.println(request);
            printWriter.flush();
            //3、从服务器读取响应
            String response = scannerNet.next();
            //4、把结果显示到界面上
            System.out.printf("req:%s resp:%s\n",request,response);
         }
      }

   }

   public static void main(String[] args) throws IOException {
      TcpEchoClient echoClient = new TcpEchoClient();
      echoClient.start();
   }
}

二、翻译服务器

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class TcpDictServer extends TcpEchoServer{
    private Map<String,String> dict = new HashMap<>();

    public TcpDictServer(int port) throws IOException {
        super(port);
        dict.put("cat","小猫");
        dict.put("dog","小狗");
        dict.put("宝贝","瑾瑾");

    }
    @Override
    public String process(String req){
        return dict.getOrDefault(req,"俺也不知道");
    }

    public static void main(String[] args) throws IOException {
        TcpDictServer server = new TcpDictServer(8000);
        server.start();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/689067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python获取文件后缀名

Python获取文件后缀名 在Python编程中&#xff0c;经常需要获取文件的后缀名&#xff0c;例如在处理文件上传、下载、压缩等操作时&#xff0c;需要对文件后缀名进行判断和处理。本文将介绍Python获取文件后缀名的两种常用方法。 方法一&#xff1a;使用split()函数 Python的…

【C语言初阶(2)】循环语句:while 循环

文章目录 1. while 语句介绍1.1 语法结构1.2 while 语句执行的流程 2. while 语句中的 break 和 continue2.1 break 介绍2.2 continue 介绍 我们已经掌握了 if 语句&#xff0c;当条件满足的情况下&#xff0c;if 语句的后的语句执行&#xff0c;反之不执行&#xff1b; 但是 i…

ChatGPT最新版多功能批量写作工具激发创作的无限可能

随着科技的不断发展&#xff0c;人工智能逐渐渗透到各个领域&#xff0c;其中包括写作领域。近年来&#xff0c;OpenAI推出的ChatGPT最新版多功能批量写作工具&#xff0c;为写作者们带来了全新的创作体验。这一工具不仅能够帮助写作者提高工作效率&#xff0c;还能够激发创作的…

chatgpt赋能python:Python获取定位的SEO指南

Python获取定位的SEO指南 什么是SEO SEO&#xff0c;即搜索引擎优化&#xff0c;是通过对网站进行优化&#xff0c;提高排名&#xff0c;从而增加搜索引擎来的流量&#xff0c;并达到提高转化率的目的。在这个数字时代&#xff0c;对于大多数网站来说&#xff0c;SEO已经成为…

idea maven 中模块显示灰色,依赖不加载

idea maven 中模块显示灰色&#xff0c;依赖刷新了几次都无法加载引入 后面发现是被MAVEN设置忽略了 去掉忽略文件然后reimport &#xff0c;就正常了

通过cifar-10数据集理解numpy数组的高(H)、宽(W)、通道数(C)

文章目录 1、CIFAR-10数据集介绍1.1 CIFAR-10数据集的构成1.2 batches.meta1.3 data_batch_n.py & test_batch.py 2、获取一张图片的data数据2.1 反序列化获得numpy数据2.2 清楚numpy中的H、W、C的含义2.3 清楚RGB图片在numpy中的表示 3、处理图片数据的代码 1、CIFAR-10数…

IDEA启动报错:Process finished with exit code 0

问题 SpringBoot项目启动后自动关闭 方案一 在pom中添加spring-boot-starter-web依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId> </dependency>方案二 在pom中…

CodeTON Round 5 (Div. 1 + Div. 2, Rated, Prizes!) A-D

1842A - Tenzing and Tsondu 题意 丁真和珍珠宝可梦对决, 每个宝可梦都有x战力, 假设有两个宝可梦, 其战力分别为a和b(a>b), 战力为a的宝可梦获胜后战力-b, 而战败的宝可梦会消失 最后还有宝可梦的人获胜 问你丁真和珍珠谁赢了 题解 显而易见, 赢下来的宝可梦可以继续打…

GcWord 6.1.4 Crack -GrapeCity Documents for Word

用于 Microsoft Word 文档的 .NET 6 API 通过代码完全控制您的 Word 文档&#xff0c;而不依赖于 Microsoft Word。 生成、加载、编辑和保存 Word 文档 基于 Microsoft Office API 的功能丰富的对象模型 从头开始或使用生成报告 报告模板 兼容多种平台&#xff0c;例如 Window…

vue-cli2 碎碎念念

vue create 和 vue init webpack 的区别&#xff1a; https://blog.csdn.net/qq_45955152/article/details/123506724 https://blog.csdn.net/qq_22182989/article/details/103611934 区别1&#xff1a; 区别2&#xff1a; 实践&#xff1a;

CadLib 4.0.2023.31601 net for Windows Crack

CadLib 4.0 for Windows&#xff1a;在 C# VB .NET 中读取、写入和显示 AutoCAD DWG 和 DXF 文件 CadLib 4.0 for Windows仅在Windows上运行&#xff0c;并且基于.NET 4.x。 CadLib 4.0读取、写入和显示 C#、VB.NET 或任何其他 .NET 语言的 AutoCAD™ DWG 和 DXF 文件。下载试…

Selenium教程__浏览器窗口大小(6)

本文将介绍如何使用Selenium来获取和设置浏览器窗口的大小&#xff0c;以及一些实际应用场景。 学习本文内容将能够轻松地控制浏览器窗口的大小&#xff0c;从而更好地适应不同的屏幕分辨率和设备&#xff0c;并确保网页在各种窗口大小下都能够良好地展示。 import time fro…

机器学习(二)逻辑回归

Logistic Regression 虽然被称为回归&#xff0c;但其实际上是分类模型&#xff0c;并常用于二分类。 Logistic 回归的本质是&#xff1a;假设数据服从这个分布&#xff0c;然后使用极大似然估计做参数的估计。 逻辑回归API介绍 sklearn.linear_model.LogisticRegression(sol…

配置apache只允许通过域名通过ssl访问

配置好IP&#xff0c;配置好bind解析 Yum安装相关软件包 进入证书目录 先用date –s 设置正确的系统时间。 创建私钥 创建证书 把私钥转换成不需要密码的 把私钥移动到私钥目录 编辑/etc/httpd/conf.d/ssl.conf 设置根目录&#xff0c;主机名。 限制80端口访问。在最后插入 设…

蜘蛛池包收录 - 百度代发排名

蜘蛛池包收录 - 百度代发排名 通话时长越长点击扣费越多吗&#xff1f; 相信这个是很多推 OCPC 用户都关注的问题&#xff0c;因为有时候接了一个电话&#xff0c;跟客户通了十几分钟&#xff0c;挂断之后发现竟然点一下扣了一百多&#xff0c;甚至二百多&#xff0c;这是什么…

Elasticsearch 分组分页排序查询

背景&#xff1a;elasticsearch聚合之后进行分页是非常常见的操作 实现思路&#xff1a; 基于es聚合函数bucket_sort、terms和指标聚合cardinality实现 实现方式&#xff1a;(以会员编码分组分页展示会员最近一条时间记录排序为例)&#xff1a; 1、查询实现 // 桶排序聚合Bu…

【数据库七】搭建MySQL主从复制和读写分离详解

详解搭建搭建MySQL主从复制和读写分离 1.案例实施&#xff1a;搭建MySQL主从复制1.1 主节点数据库&#xff08;CentOS 7-5&#xff09;1.2 从节点数据库&#xff08;CentOS 7-6&#xff09;1.3 从节点数据库&#xff08;CentOS 7-7&#xff09;1.4 验证MySQL主从复制 2.案例实施…

Scala的foldLeft与foldRight详解

foldLeft与foldRight是特质TraversableOnce定义的高阶函数&#xff0c;直译过来为向左折叠和向右折叠。具体实现如下摘出的代码所示&#xff1a; trait TraversableOnce[A] extends Any with GenTraversableOnce[A] {deprecated("Use foldLeft instead of /:", &quo…

lesson7-1 Zigbee协议栈的使用

目录 协议栈的使用 协议栈的安装和协议栈工程创建 协议栈工程配置 选项卡选择 用户代码编写注意 信道选择及PANID分配 协议栈的使用 协议栈的安装和协议栈工程创建 首先进行协议栈的安装 如何创建自己的协议栈工程&#xff1a; &#xff08;1&#xff09;先把整个协议…

ansible实训-Day1(Liunx基础问题总结及ansible安装环境前置部署)

一、前言 该篇是对本学期Ansible实训第一天内容的原理性总结&#xff0c;主要包括Liunx相关问题等基础性的问题总结以及ansible安装环境的前置部署。 二、Liunx是什么 Linux是一种自由和开放源代码的Unix操作系统&#xff0c;最初由芬兰人Linus Torvalds于1991年创建。与其他许…