网络编程套接字之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 学习之接口
接口:对值所具有的结构进行类型检查,称为“鸭式变型法”或“结构性子类型化” 基本使用 interface LabelledValue {label: string; }function printLabel(labelledObj: LabelledValue) {console.log(labelledObj.label); }let myObj {size: 10, label:…...
原码反码补码
在计算机中,负数都是以补码的形式存放的, 正数的原码、反码、补码完全一致。 原码:指的是正数的二进制或负数的二进制, 负数的二进制(原码),其实就是在正数的二进制的最高位前面加一个符号位 1。…...
大数据选股智能推荐系统V1.0-1
很长时间没有发布博客了,这段时间个人确实有点忙。另外一方面在这段时间我也没有闲着。自己研发了一套大数据选股的智能推荐系统。废话不说,我们先来看这套系统:登录页面:(技术点:验证码的生成)…...
调研生成GIF表情包之路
调研阶段 gifshot.js合成GIF 可以从媒体流、视频或图像创建动画 GIF 的 JavaScript 库。 csdn地址:https://blog.csdn.net/qq_16494241/article/details/125717405 分解GIF图片、合成GIF图片 两步走: 1、分解GIF图片 libgif-js:JavaScrip…...
【RocketMQ】源码详解:生产者启动与消息发送流程
消息发送 生产者启动 入口 : org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl#start(boolean) 生产者在调用send()方法发送消息之前,需要调用start进行启动, 生产者启动过程中会启动一些服务和线程 启动过程中会启动MQClientInstance, 这个实例是针对一个项…...
信息安全(一)
思维导图 一、AES加解密 1.概述 1.1 概念 AES: 高级加密标准(Advanced Encryption Standard)是一种对称加密的区块加密标准。 (1)替代DES的新一代分组加密算法 (2)支持三种长度密钥&#x…...
企业多会场视频直播(主会场、分会场直播)实例效果
阿酷TONY 2023-2-16 长沙 活动直播做多会场切换功能(主会场、分会场、会场一、会场二、会场三自由切换) 企业多会场视频直播(主会场、分会场直播)实例效果 特点:支持PC端,也支持移动端观看,会…...
线性代数速览(一)行列式
文章目录行列式🌻 行列式的定义🌼 行列式的性质🌷 一些定理🥀 行列式的计算🌺 克莱姆法则行列式 行列式的本质,就是一个数值。 🌻 行列式的定义 有三种定义:1、按行展开ÿ…...
恭喜山东翰林“智慧园区管理系统”获易知微可视化设计大赛二等奖
数字化经济发展是全球经济发展的重中之重,“数字孪生(Digital Twin)”这一词汇正在成为学术界和产业界的一个热点。数字孪生作为近年来的新兴技术,其与国民经济各产业融合不断深化,推动着各大产业数字化、网络化、智能…...
gulp简单使用
gulp gulp的核心理念是task runner 可以定义自己的一系列任务 等待任务被执行 基于文件stream的构建流 我们可以使用gulp的插件体系来完成某些任务 webpack的核心理念是module bundler webpack是一个模块化的打包工具 可以使用各种各样的loader来加载不同的模块 可以使用各种…...
ce认证机构如何选择?
CE认证想必大家都已经有所了解,它是产品进入欧盟销售的通行证,那么我们在办理CE认证时该怎么进行选择?带大家了解一下CE认证机构,以及该怎么去进行选择? 以下信息由证果果编辑整理,更多认证机构信息请到证果果网站查看。找机构…...
全网招募P图高手!阿里巴巴持续训练鉴假AI
P过的证件如何鉴定为真?三千万网友都晒出了与梅西的合影?图像编辑技术的普及让人人都能P图,但也带来“假图”识别难题,甚至是欺诈问题。 为此,阿里安全联合华中科技大学国家防伪工程中心、国际文档分析识别方向的唯一顶…...
webrtc QOS笔记一 Neteq直方图算法浅读
webrtc QOS笔记一 Neteq直方图算法浅读 文章目录webrtc QOS笔记一 Neteq直方图算法浅读Histogram Algorithm获取目标延迟遗忘因子曲线Histogram Algorithm DelayManager::Update()->Histogram::Add() 会根据计算的iat_packet(inter arrival times, 实际包间间隔 / 打包时长…...
细分和切入点
本文重点介绍做SEO网站细分和切入点的方法:当我们的行业和关键词竞争性比较大的时候,我们可以考虑对行业或者产品做细分,从而找到切入点。可以按照以下三个方面进行细分。1、按城市细分例如:A:餐饮培训,当前…...
iOS创建Universal Link
iOS 9之前,一直使用的是URL Schemes技术来从外部对App进行跳转,但是iOS系统中进行URL Schemes跳转的时候如果没有安装App,会提示无法打开页面的提示。 iOS 9之后起可以使用Universal Links技术进行跳转页面,这是一种体验更加完美的…...
RuoYi-Vue搭建(若依)
项目简介 RuoYi-Vue基于SpringBootVue前后端分离的Java快速开发框架1.前端采用Vue、Element UI2.后端采用Spring Boot、Spring Security、Redis & Jwt3.权限认证使用Jwt,支持多终端认证系统4.支持加载动态权限菜单,多方式轻松权限控制5.高效率开发&a…...
进程组和用处
进程组:一个或多个进程的集合,进程组id是一个正整数。组长进程:进程组id 进程id组长进程可以创建一个进程组,创建该进程组的进程,终止了,只要进程组有一个进程存在,进程组就存在,与…...
Nacos集群+Nginx负载均衡
搭建Nacos集群 注意: 3个或3个以上Nacos节点才能构成集群。要求服务器内存分配最好大于6G以上(如果不够则需修改nacos启动脚本中的默认内存配置)根据nacos自带的mysql建库脚本建立对应数据库(/conf/nacos-mysql.sql)如果是三台服…...
TypeScript 学习之类型兼容
TypeScript 的类型兼容性是基于结构子类型的。 结构类型是一种只使用其成员来描述类型的方式。 interface Named {name: string; }class Person {name: string; }let p: Named; p new Person();// 赋值成功,因为都是结构类型,只要Person 类型的包含 Nam…...
Linux软件管理RPM
目录 前言 RPM软件管理程序:rpm RPM默认安装的路径 PRM讲解前准备工作 RPM安装(install) RPM查询(query) RPM卸载(erase) RPM升级与更新(upgrade/freshen) RPM重…...
01背包问题
背包问题的递归解决过程如下: 第一步明确思路 在解决问题之前,为描述方便,首先定义一些变量:Vi表示第 i 个物品的价值,Wi表示第 i 个物品的体积,定义V(i,j):当前背包容量 j,前 i 个…...
14_FreeRTOS二值信号量
目录 信号量的简介 队列与信号量的对比 二值信号量 二值信号量相关API函数 实验源码 信号量的简介 信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。 假设有一个人需要在停车场停车 1.首先判断停车场是否还有空车位(判断信号量是否有资源) 2.停车场正好…...
JavaScript随手笔记---轮播图(点击切换)
💌 所属专栏:【JavaScript随手笔记】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &#…...
机器人学 markdown数学公式常用语法
参考链接1 本文包含了markdown常用的数学公式,按照目录可查询选用 初始类 行内数学公式均用两个符号包裹行间数学公式均用两个符号包裹 行间数学公式均用两个符号包裹行间数学公式均用两个符号包裹,用于表示重要的、需在行间单独列出的公式 $行内数学…...
如何使用 Python 语言来编码和解码 JSON 对象
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写。 JSON 函数 使用 JSON 函数需要导入 json 库:import json。 函数 描述 json.dumps 将 Python 对象编码成 JSON 字符串 json.loads 将已编码的 JSON 字符串解码为 Pyth…...
【蓝桥云课】求正整数的约数个数
一、求正整数n的约数个数 方法一(常用算法):从1到n逐一判断其能否整除n,若能整除n即为n的约数,否则不是n的约数。 方法二:从1到n\sqrt{n}n逐一判断是否为n的约数,当n\sqrt{n}n为n的约数时,个数加1&…...
崂山区城乡建设局网站/网站查询器
Resharper是一款很优秀的重构工具,已经习惯了Resharper快捷键,利用Resharper做重构,TDD开发,很爽。唯一缺点就是低配置机器上速度很慢,容易拖死VS, 为此我我专门把我的本本换成6G内存,现在感觉顺…...
wap网站制作工具/如何创建一个网址
Scala集合的mutable和immutable解释概述集合API概述概述 Scala 集合类系统地区分了可变的和不可变的集合。可变集合可以在适当的地方被更新或扩展。这意味着你可以修改,添加,移除一个集合的元素。而不可变集合类,相比之下,永远不会…...
内蒙古建设工程交易中心网站/手机百度浏览器
TimeLimitingCollector 包装其他的收集器,当查询超过指定时间时通过抛出TimeExceededException异常来中止搜索。通过一个被包装的收集器,一个时钟定时器和超时时间来构造TimeLimitingCollector对象。setBaseline(long clockTime):在包…...
辽宁网站建设/详情页设计
主要软件包, 1. httpd-2.2.6.tar.gz 2. mysql-5.0.45-linux-i686-glibc23.tar.gz ( 这个版本是已编译好的压缩包,解压后稍做配置即可使用 ) 3. php-5.2.5.tar.gz 安装 php 所需的软件包(其中 libxml2 是安装 php5 必须的 . ) 1. l…...
网站前置审批专项/国际婚恋网站排名
环境: 电脑:联想E14 系统:Windows 10 专业版 64位 VMware 16.0 :Ubuntu20.04 问题描述: 如何更新国内源,原因是安装ssh没成功 解决方案: 1.备份原来的源 sudo cp /etc/apt/sources.list…...
用wordpress好吗/黑龙江头条今日新闻
欢迎您戳蓝色字“工数平台”持续关注我们哟!导言在当今中国的各个领域,“弯道超车”是个经常被提及的口号,然而常识和交规告诉我们,弯道不仅不能超车还得减速,超车极其危险。仔细解读“弯道超车”,其实还暗…...