当前位置: 首页 > news >正文

网络编程套接字之TCP

在这里插入图片描述

文章目录

  • 一、TCP流套接字编程
    • ServerSocket
    • Socket
    • TCP长短连接
  • 二、TCP回显服务器客户端
    • 服务器
    • 客户端
    • 并发服务器
    • UDP与TCP

一、TCP流套接字编程

我们来一起学习一下TCP socket api的使用,这个api与我们之前学习的IO流操作紧密相关,如果对IO流还不太熟悉的,可以看看这篇IO流操作

ServerSocket

顾名思义,ServerSocket是创建TCP服务器的Socket对象

构造方法作用
ServerSocket(int port)创建一个服务器套接字Socket,并指定端口号
方法作用
Socket accept()开始监听指定端口,有客户端连接时,返回一个服务端Socket对象,并基于该Socket对象与客户端建立连接,否则阻塞等待
void close()关闭此套接字

Socket

我们这里的Socket既是客户端的Socket,也可能是服务器接收到客户端连接后,返回的服务器Socket,不论是那个Socket,都是双方建立连接后,保存对方信息,进行收发数据的。

构造方法作用
Socket(String host,int port)创建一个客户端Socket对象,并与对应IP主机,对应端口的进程进行连接
方法作用
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回套接字的输入流
OutputStream getOutputStream()返回套接字的输出流

TCP长短连接

顾名思义,我们的TCP的长短连接,就表示我们TCP建立连接后,什么时候关闭连接就决定了是长连接还是短链接。
短连接: 在每次接收到数据并返回响应后,关闭连接。也就是说短连接只能收发一次数据。
长连接: 一直保持连接的状态,不关闭连接,双方可以不停的收发数据。

两者各有优缺,短连接适用于客户端请求频率不高的场景,浏览网页等。长连接适用于客户端与服务器频繁通信的场景,视频通话等。

二、TCP回显服务器客户端

服务器

有了昨天UDP实现的基础,今天我们的TCP实现已经有些部分就比较容易理解了。

public class EchoServer {private ServerSocket serverSocket = null;public EchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}
}

先创建TCP服务器Socket对象,并指定端口号。

Socket clientSocket = serverSocket.accept();

与客户端进行连接,如果没有获取到连接,则会发生阻塞等待,每获取到一个客户端连接就会返回一个Socket对象,该Socket对象是专门负责与连接的客户端进行通信的。
我们获取到的每一个Socket对象,可能会进行多次通信,所以我们获取到连接后,将通信封装成一个方法。

private void processCoonection(Socket clientSocket) {System.out.printf("[%s:%d] 客户端上线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {}catch (IOException e) {e.printStackTrace();}finally {try{clientSocket.close();}catch (IOException e) {e.printStackTrace();}}}

我们先获取与输出输入流,因为需要释放我们直接将它们放到try()中,然后在finally里释放Socket对象资源。

Scanner scanner = new Scanner(inputStream);if(!scanner.hasNext()) {//数据已经读完了System.out.printf("[%s:%d] 客户端下线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}String request = scanner.next();

我们将输入流封装到Scanner里,从控制台输入,然后判断控制台是否还有数据输入,如果没有数据输入就退出,然后获取客户端的请求。

/直接返回客户端的请求String response = process(request);//将输出流封装成打印流PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);printWriter.flush();System.out.printf("[%s:%d] req: %s;resp: %s\n",clientSocket.getInetAddress().toString(), clientSocket.getPort(),request, response);

在这里插入图片描述

public class EchoServer {private ServerSocket serverSocket = null;public EchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");while (true) {Socket clientSocket = serverSocket.accept();processCoonection(clientSocket);}}private void processCoonection(Socket clientSocket) {System.out.printf("[%s:%d] 客户端上线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {while (true) {Scanner scanner = new Scanner(inputStream);if(!scanner.hasNext()) {//数据已经读完了System.out.printf("[%s:%d] 客户端下线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}String request = scanner.next();//直接返回客户端的请求String response = process(request);//将输出流封装成打印流PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);printWriter.flush();System.out.printf("[%s:%d] req: %s;resp: %s\n",clientSocket.getInetAddress().toString(), clientSocket.getPort(),request, response);}}catch (IOException e) {e.printStackTrace();}finally {try{clientSocket.close();}catch (IOException e) {e.printStackTrace();}}}public String process(String request) {return request;}
}

我们现在实现的这个TCP server有个致命的缺点,一次只能处理一个客户端,等我们写完客户端再来分析。

客户端

public class EchoClient {private Socket socket = null;public EchoClient(String serverIp,int serverPort) throws IOException {//我们TCP的Socket对象能够识别点分十进制的IP//我们在创建对象的时候,就会与服务器进行连接socket = new Socket(serverIp,serverPort);}
}

我们在new 这个对象的过程,就会触发TCP建立连接的过程,如果我们客户端没有这部分代码,那么服务器就会在accept进行阻塞等待。

public void start() {System.out.println("客户端启动!");Scanner scanner = new Scanner(System.in);try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while (true) {System.out.print("> ");String request = scanner.next();if(request.equals("exit")) {System.out.println("客户端退出!");break;}PrintWriter printWriter = new PrintWriter(outputStream);printWriter.flush();Scanner respScanner = new Scanner(inputStream);String response = respScanner.next();System.out.println(response);}}catch (IOException e) {e.printStackTrace();}}

我们客户端的收发数据与服务器大差不差,这里就不在一一解释了。
在这里插入图片描述
在这里插入图片描述
分别启动客户端服务器程序。

在这里插入图片描述
在这里插入图片描述
可以成功的收发数据,但是我们当前代码有一个很严重的问题,服务器同一时刻只能处理一个连接,这样是很鸡肋的,我们对服务器进行更新。

并发服务器

我们看观察一下我们服务器的代码。
在这里插入图片描述
当我们客户端连接上这个服务器的时候,就执行到processConnection方法的while循环中,只要该方法不结束,我们的accpet就无法获取到第二个客户端socket对象。
那么我们如何解决这个问题呢?
使用多线程,我们的主线程专门负责进行accept,每收到一个连接,创建新线程,由新线程来负责处理这个新的客户端。

public void start() throws IOException {System.out.println("服务器启动!");while (true) {Socket clientSocket = serverSocket.accept();Thread t = new Thread(() -> {processCoonection(clientSocket);});t.start();}}

我们可以使用多线程来解决这个问题,但是现在每获取到一个连接就会创建一个线程,如果同一时刻连接过多,我们创建了大量线程,资源全部耗费在了线程切换上面了,我们可以使用线程池来提升效率。

public void start() throws IOException {System.out.println("服务器启动!");ExecutorService threadPool = Executors.newCachedThreadPool();while (true) {Socket clientSocket = serverSocket.accept();threadPool.submit(() -> {processCoonection(clientSocket);});}}

尽管我们使用了线程池了,但还是不够,如果我们的客户端非常多,而且都迟迟不断开,就会导致我们会有很多线程,对于我们来说是一个很大的负担。
能否有办法解决单机支持更大量客户端的问题呢?也是经典的C10M(单机处理1KW个客户端)问题
这里并不是说单机真正能处理1KW个客户端,只是表达说客户端的量非常大,针对我们上述多线程的版本,我们的机器是承受不了这么多线程的开销的,那么是否有办法一个线程处理很多客户端连接呢? 这就是IO多路复用,IO多路转接技术
给线程安排一个集合,这个集合放了一堆连接,我们线程负责监听集合,那个连接有数据来了,就处理那个连接。虽然我们的连接有很多,但是我们这里的连接并不是严格意义上的同时,也是有先后的,我们的操作系统里,提供了一些API,比如select,poll,epoll,我们的java里,也提供了一组NIO这样的类,封装了上述技术。

UDP与TCP

我们学习了TCP与UDP的网络编程后,来进行一个对比。
TCP:
在这里插入图片描述
UDP:
在这里插入图片描述

相关文章:

网络编程套接字之TCP

文章目录一、TCP流套接字编程ServerSocketSocketTCP长短连接二、TCP回显服务器客户端服务器客户端并发服务器UDP与TCP一、TCP流套接字编程 我们来一起学习一下TCP socket api的使用,这个api与我们之前学习的IO流操作紧密相关,如果对IO流还不太熟悉的&am…...

网络与串口调试工具TCPCOM

TCPCOM,网络与串口二合一调试助手,将网络调试助手与串口调试助手合二为一,绿色软件,简单高效。【软件特色】 1. 支持中英文双语言,自动根据操作系统环境选择系统语言类型; 2. 支持ASCII/Hex发送,发送和接收…...

数据库常用命令

文章目录1. 数据库操作命令1.进入数据库2.查看数据库列表信息3.查看数据库中的数据表信息2.SQL语句命令1. 创建数据表2. 基本查询语句3. SQL排序4. SQL分组统计5. 分页查询6. 多表查询7.自关联查询8.子查询1. 数据库操作命令 1.进入数据库 mysql -uroot -p2.查看数据库列表信…...

PTA复习

函数 6-1 学生类的构造与析构 #include<bits/stdc.h> using namespace std; class Student {int num;string name;char sex; public:Student(int n,string nam,char s):num(n),name(nam),sex(s){cout<<"Constructor called."<<endl;}void display…...

TypeScript 学习之接口

接口&#xff1a;对值所具有的结构进行类型检查&#xff0c;称为“鸭式变型法”或“结构性子类型化” 基本使用 interface LabelledValue {label: string; }function printLabel(labelledObj: LabelledValue) {console.log(labelledObj.label); }let myObj {size: 10, label:…...

原码反码补码

在计算机中&#xff0c;负数都是以补码的形式存放的&#xff0c; 正数的原码、反码、补码完全一致。 原码&#xff1a;指的是正数的二进制或负数的二进制&#xff0c; 负数的二进制&#xff08;原码&#xff09;&#xff0c;其实就是在正数的二进制的最高位前面加一个符号位 1。…...

大数据选股智能推荐系统V1.0-1

很长时间没有发布博客了&#xff0c;这段时间个人确实有点忙。另外一方面在这段时间我也没有闲着。自己研发了一套大数据选股的智能推荐系统。废话不说&#xff0c;我们先来看这套系统&#xff1a;登录页面&#xff1a;&#xff08;技术点&#xff1a;验证码的生成&#xff09;…...

调研生成GIF表情包之路

调研阶段 gifshot.js合成GIF 可以从媒体流、视频或图像创建动画 GIF 的 JavaScript 库。 csdn地址&#xff1a;https://blog.csdn.net/qq_16494241/article/details/125717405 分解GIF图片、合成GIF图片 两步走&#xff1a; 1、分解GIF图片 libgif-js&#xff1a;JavaScrip…...

【RocketMQ】源码详解:生产者启动与消息发送流程

消息发送 生产者启动 入口 : org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl#start(boolean) 生产者在调用send()方法发送消息之前,需要调用start进行启动, 生产者启动过程中会启动一些服务和线程 启动过程中会启动MQClientInstance, 这个实例是针对一个项…...

信息安全(一)

思维导图 一、AES加解密 1.概述 1.1 概念 AES&#xff1a; 高级加密标准&#xff08;Advanced Encryption Standard&#xff09;是一种对称加密的区块加密标准。 &#xff08;1&#xff09;替代DES的新一代分组加密算法 &#xff08;2&#xff09;支持三种长度密钥&#x…...

企业多会场视频直播(主会场、分会场直播)实例效果

阿酷TONY 2023-2-16 长沙 活动直播做多会场切换功能&#xff08;主会场、分会场、会场一、会场二、会场三自由切换&#xff09; 企业多会场视频直播&#xff08;主会场、分会场直播&#xff09;实例效果 特点&#xff1a;支持PC端&#xff0c;也支持移动端观看&#xff0c;会…...

线性代数速览(一)行列式

文章目录行列式&#x1f33b; 行列式的定义&#x1f33c; 行列式的性质&#x1f337; 一些定理&#x1f940; 行列式的计算&#x1f33a; 克莱姆法则行列式 行列式的本质&#xff0c;就是一个数值。 &#x1f33b; 行列式的定义 有三种定义&#xff1a;1、按行展开&#xff…...

恭喜山东翰林“智慧园区管理系统”获易知微可视化设计大赛二等奖

数字化经济发展是全球经济发展的重中之重&#xff0c;“数字孪生&#xff08;Digital Twin&#xff09;”这一词汇正在成为学术界和产业界的一个热点。数字孪生作为近年来的新兴技术&#xff0c;其与国民经济各产业融合不断深化&#xff0c;推动着各大产业数字化、网络化、智能…...

gulp简单使用

gulp gulp的核心理念是task runner 可以定义自己的一系列任务 等待任务被执行 基于文件stream的构建流 我们可以使用gulp的插件体系来完成某些任务 webpack的核心理念是module bundler webpack是一个模块化的打包工具 可以使用各种各样的loader来加载不同的模块 可以使用各种…...

ce认证机构如何选择?

CE认证想必大家都已经有所了解&#xff0c;它是产品进入欧盟销售的通行证&#xff0c;那么我们在办理CE认证时该怎么进行选择?带大家了解一下CE认证机构&#xff0c;以及该怎么去进行选择? 以下信息由证果果编辑整理&#xff0c;更多认证机构信息请到证果果网站查看。找机构…...

全网招募P图高手!阿里巴巴持续训练鉴假AI

P过的证件如何鉴定为真&#xff1f;三千万网友都晒出了与梅西的合影&#xff1f;图像编辑技术的普及让人人都能P图&#xff0c;但也带来“假图”识别难题&#xff0c;甚至是欺诈问题。 为此&#xff0c;阿里安全联合华中科技大学国家防伪工程中心、国际文档分析识别方向的唯一顶…...

webrtc QOS笔记一 Neteq直方图算法浅读

webrtc QOS笔记一 Neteq直方图算法浅读 文章目录webrtc QOS笔记一 Neteq直方图算法浅读Histogram Algorithm获取目标延迟遗忘因子曲线Histogram Algorithm DelayManager::Update()->Histogram::Add() 会根据计算的iat_packet(inter arrival times, 实际包间间隔 / 打包时长…...

细分和切入点

本文重点介绍做SEO网站细分和切入点的方法&#xff1a;当我们的行业和关键词竞争性比较大的时候&#xff0c;我们可以考虑对行业或者产品做细分&#xff0c;从而找到切入点。可以按照以下三个方面进行细分。1、按城市细分例如&#xff1a;A&#xff1a;餐饮培训&#xff0c;当前…...

iOS创建Universal Link

iOS 9之前&#xff0c;一直使用的是URL Schemes技术来从外部对App进行跳转&#xff0c;但是iOS系统中进行URL Schemes跳转的时候如果没有安装App&#xff0c;会提示无法打开页面的提示。 iOS 9之后起可以使用Universal Links技术进行跳转页面&#xff0c;这是一种体验更加完美的…...

RuoYi-Vue搭建(若依)

项目简介 RuoYi-Vue基于SpringBootVue前后端分离的Java快速开发框架1.前端采用Vue、Element UI2.后端采用Spring Boot、Spring Security、Redis & Jwt3.权限认证使用Jwt&#xff0c;支持多终端认证系统4.支持加载动态权限菜单&#xff0c;多方式轻松权限控制5.高效率开发&a…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...