网络编程TCP

White graces:个人主页

🙉专栏推荐:Java入门知识🙉

🙉 内容推荐:Java网络编程(下)🙉

🐹今日诗词: 壮士当唱大风哥, 宵小之徒能几何?🐹


⛳️点赞 ☀️收藏⭐️关注💬卑微小博主🙏

⛳️点赞 ☀️收藏⭐️关注💬卑微小博主🙏


目录

TCP字节流套接字编程

回显服务器

服务端(有点问题的)

空白符问题

客户端

代码问题

原因

解决办法一

服务器(没问题的代码)

解决方法二

线程池的服务端代码(没问题的代码)

美图分享


TCP字节流套接字编程

TCP也有两个类用于网络编程

SeverSocket: 用于TCP字节数据进行网络通信, 创建了TCP服务端API, 专门用于服务器的

Socket: 客户端和服务器都能够使用, 客户端使用可以建立和服务器的通信

服务器可使用可以监听客户端的连接请求

值得注意的是: TCP是字节流传输, 传输单位是字节(byte), 不需要向UDP那样专门搞出一个类来用于传输数据报

SeverSocket类

构造方法: SeverSocket(int Port)

SeverSocket函数方法

函数方法

Socket类

构造方法: Socket(String host, int port)

Socket函数方法

回显服务器

服务端(有点问题的)

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;public class TcpSever {private ServerSocket serverSocket = null;public TcpSever(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器!启动");while (true) {Socket clientsocket = serverSocket.accept();//这里和UDP不一样,UDP是直接接收请求, 而TCP需要先和客户端建立连接, 才能进一步处理请求processmethod(clientsocket);//客户端请求结束时应该调用close方法,释放资源, 所以在processmethod方法里调用close方法关闭}}private void processmethod(Socket clientsocket) throws IOException {System.out.printf("[%s:%d]客户端成功连接服务器\n", clientsocket.getInetAddress(), clientsocket.getPort());//打印日志, 接下来就是响应请求了try (OutputStream outputStream = clientsocket.getOutputStream();InputStream inputStream = clientsocket.getInputStream()){//从clientsocket中获取流对象, 对数据进一步处理, 把他们放到try()里,结束会自动调用close方法Scanner scanner = new Scanner(inputStream);while (true) {//客户端建立连接后, 可能会发送很多请求, 需要循环处理//inputStream.read();//读取请求,这样就得到了字符数组,接下来转成字符串, 这样写很麻烦我们可以使用Scanner一步到位if (!scanner.hasNext()) {//读取前判断有没有数据, 没有数据说明连接断开了System.out.printf("[%s:%d]客户端断开连接\n", clientsocket.getInetAddress(), clientsocket.getPort());break;}String request = scanner.next();//读取请求, next()方法读取数据是读到空白符String response = process(request);//根据请求计算响应System.out.printf("[%s:%d] request = %s response = %s",clientsocket.getInetAddress(), clientsocket.getPort(), request, response);//打印日志outputStream.write(response.getBytes());//将响应数据写回客户端}} finally {clientsocket.close();//客户端断开连接调用close方法释放资源}}private String process(String request) {//回显服务器,前面next()方法读取数据读到空白符停止,当我们把数据写回客户端是要把空白符加上return request + "\n";}public static void main(String[] args) throws IOException {TcpSever tcpSever = new TcpSever(9090);tcpSever.start();}
}

空白符问题

空白符是一类分隔符的统称, 不是一个空格, 常见空白符有很多

TCP字节流传输常见的问题就是空白符问题

发送请求和读取请求时都需要考虑分隔符

因为发送的数据带有空白符,当使用next方法读取数据时, 会忽略空白符, 因此当我们向客户端写回请求时需要把空白符加回去, 保持格式的统一性

客户端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;public class TcpClient {private Socket socket = null;public TcpClient(String SeverIP, int SeverPort) throws IOException {socket = new Socket(SeverIP, SeverPort);}private void start() throws IOException {System.out.println("客户端, 启动!");Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {//获取流对象, 把数据传入流对象之后, 等待服务器响应即可, 这里和UDP不同, UDP是把数据打包发送到服务器//而TCP客户端已经和服务器建立连接了, 中间通道已经打通, 将数据传入流对象等待响应即可//流对象扮演的角色就像是中间商, 服务器和客户端的操作都要经过流对象Scanner scannerinpuStream = new Scanner(inputStream);while (true) {System.out.print("请输入你要发送的请求: ");String request = scanner.next();request += "\n";//next方法会忽略\n, 为了保持服务端next方法一致, 手动加上\noutputStream.write(request.getBytes());//将请求写到流对象中if(!scannerinpuStream.hasNext()) {//没有数据说明读取完毕了break;}String response = scannerinpuStream.next();//从服务器获取响应System.out.println(response);//将数据打印出来}}}public static void main(String[] args) throws IOException {TcpClient tcpClient = new TcpClient("127.0.0.1", 9090);tcpClient.start();}
}

运行效果

代码问题

这种写法只能对一个客户端提供服务,  当我们启动多个客户端时

原因

解决办法一

把processmethod方法放到多线程的环境下运行


服务器(没问题的代码)

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;public class TcpSever {private ServerSocket serverSocket = null;public TcpSever(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器!启动");while (true) {Socket clientsocket = serverSocket.accept();//这里和UDP不一样,UDP是直接接收请求, 而TCP需要先和客户端建立连接, 才能进一步处理请求Thread thread = new Thread(() -> {try {processmethod(clientsocket);//客户端请求结束时应该调用close方法,释放资源, 所以在processmethod方法里调用close方法关闭} catch (IOException e) {throw new RuntimeException(e);}});thread.start();}}private void processmethod(Socket clientsocket) throws IOException {System.out.printf("[%s:%d]客户端成功连接服务器\n", clientsocket.getInetAddress(), clientsocket.getPort());//打印日志, 接下来就是响应请求了try (OutputStream outputStream = clientsocket.getOutputStream();InputStream inputStream = clientsocket.getInputStream()){//从clientsocket中获取流对象, 对数据进一步处理, 把他们放到try()里,结束会自动调用close方法Scanner scanner = new Scanner(inputStream);while (true) {//客户端建立连接后, 可能会发送很多请求, 需要循环处理//inputStream.read();//读取请求,这样就得到了字符数组,接下来转成字符串, 这样写很麻烦我们可以使用Scanner一步到位if (!scanner.hasNext()) {//读取前判断有没有数据, 没有数据说明连接断开了System.out.printf("[%s:%d]客户端断开连接\n", clientsocket.getInetAddress(), clientsocket.getPort());break;}String request = scanner.next();//读取请求, next()方法读取数据是读到空白符String response = process(request);//根据请求计算响应System.out.printf("[%s:%d] request = %s response = %s",clientsocket.getInetAddress(), clientsocket.getPort(), request, response);//打印日志outputStream.write(response.getBytes());//将响应数据写回客户端}} finally {clientsocket.close();//客户端断开连接调用close方法释放资源}}private String process(String request) {//回显服务器,前面next()方法读取数据读到空白符停止,当我们把数据写回客户端是要把空白符加上return request + "\n";}public static void main(String[] args) throws IOException {TcpSever tcpSever = new TcpSever(9090);tcpSever.start();}
}

解决方法二

把代码放到线程池中, 这种方法更合适, 不仅解决了只能连接一个客户端, 又能减少线程创建销毁的开销

线程池的服务端代码(没问题的代码)

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;public class TcpSever {private ServerSocket serverSocket = null;public TcpSever(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器!启动");ExecutorService pool = Executors.newCachedThreadPool();//这个线程池可以自动扩容while (true) {Socket clientsocket = serverSocket.accept();//这里和UDP不一样,UDP是直接接收请求, 而TCP需要先和客户端建立连接, 才能进一步处理请求pool.submit(new Runnable() {@Overridepublic void run() {try {processmethod(clientsocket);//客户端请求结束时应该调用close方法,释放资源, 所以在processmethod方法里调用close方法关闭} catch (IOException e) {throw new RuntimeException(e);}}});}}private void processmethod(Socket clientsocket) throws IOException {System.out.printf("[%s:%d]客户端成功连接服务器\n", clientsocket.getInetAddress(), clientsocket.getPort());//打印日志, 接下来就是响应请求了try (OutputStream outputStream = clientsocket.getOutputStream();InputStream inputStream = clientsocket.getInputStream()){//从clientsocket中获取流对象, 对数据进一步处理, 把他们放到try()里,结束会自动调用close方法Scanner scanner = new Scanner(inputStream);while (true) {//客户端建立连接后, 可能会发送很多请求, 需要循环处理//inputStream.read();//读取请求,这样就得到了字符数组,接下来转成字符串, 这样写很麻烦我们可以使用Scanner一步到位if (!scanner.hasNext()) {//读取前判断有没有数据, 没有数据说明连接断开了System.out.printf("[%s:%d]客户端断开连接\n", clientsocket.getInetAddress(), clientsocket.getPort());break;}String request = scanner.next();//读取请求, next()方法读取数据是读到空白符String response = process(request);//根据请求计算响应System.out.printf("[%s:%d] request = %s response = %s",clientsocket.getInetAddress(), clientsocket.getPort(), request, response);//打印日志outputStream.write(response.getBytes());//将响应数据写回客户端}} finally {clientsocket.close();//客户端断开连接调用close方法释放资源}}private String process(String request) {//回显服务器,前面next()方法读取数据读到空白符停止,当我们把数据写回客户端是要把空白符加上return request + "\n";}public static void main(String[] args) throws IOException {TcpSever tcpSever = new TcpSever(9090);tcpSever.start();}
}


美图分享

✨🎆谢谢你的阅读和耐心!祝愿你在编程的道路上取得更多的成功与喜悦!"🎆✨🎄

⭐️点赞收藏加关注,学习知识不迷路⭐️

🎉✔️💪🎉✔️💪🎉✔️💪🎉✔️💪🎉

👍😏⛳️点赞☀️收藏⭐️关注😏👍

👍😏⛳️点赞☀️收藏⭐️关注😏👍

👍😏⛳️点赞☀️收藏⭐️关注😏👍

🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

音视频开发17 FFmpeg 音频解码- 将 aac 解码成 pcm

这一节,接 音视频开发12 FFmpeg 解复用详情分析,前面我们已经对一个 MP4文件,或者 FLV文件,或者TS文件进行了 解复用,解出来的 视频是H264,音频是AAC,那么接下来就要对H264和AAC进行处理,这一节…

ChatGPT交卷2024年高考新课标I卷语文关于AI方面的作文试题

2024年新课标I卷作文试题: 阅读下面的材料,根据要求写作。(60分) 随着互联网的普及、人工智能的应用,越来越多的问题能很快得到答案。那么,我们的问题是否会越来越少? 以上材料引发了你怎样的…

Nginx03-动态资源和LNMP介绍与实验、自动索引模块、基础认证模块、状态模块

目录 写在前面Nginx03案例1 模拟视频下载网站自动索引autoindex基础认证auth_basic模块状态stub_status模块模块小结 案例2 动态网站(部署php代码)概述常见的动态网站的架构LNMP架构流程数据库Mariadb安装安全配置基本操作 PHP安装php修改配置文件 Nginx…

os和os.path模块

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 目录也称文件夹,用于分层保存文件。通过目录可以分门别类地存放文件。我们也可以通过目录快速找到想要的文件。在Python中,并…

写入文件内容

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在实例01中,虽然创建并打开一个文件,但是该文件中并没有任何内容,它的大小是0KB。Python的文件对象提供了write()…

人类语言处理nlp部分笔记——二、BERT和它的家族-介绍和微调

参考自李宏毅课程-人类语言处理 二、BERT和它的家族-介绍和微调 1. What is pre-train model 这里所说的pre-train model是输入一串tokens,能够输出一串vectors,且每个vector可以表示对应的语义的模型,这些vectors也被称作为embeddings。以…

google的chromedriver最新版下载地址

Chrome for Testing availability (googlechromelabs.github.io) 复制对应的地址跳转进去即可下载,下载前先看下自己google浏览器版本,找到对应的版本号去下载,把解压缩的exe放到google浏览器目录下。

一键生成迷宫-Word插件-大珩助手新功能

Word大珩助手是一款功能丰富的Office Word插件,旨在提高用户在处理文档时的效率。它具有多种实用的功能,能够帮助用户轻松修改、优化和管理Word文件,从而打造出专业而精美的文档。 【新功能】迷宫生成器 1、可自定义迷宫大小; …

古字画3d立体在线数字展览馆更高效便捷

在数字时代的浪潮中,大连图书馆以崭新的面貌跃然屏幕之上——3D全景图书馆。这座承载着城市文化精髓与丰富知识资源的数字图书馆,利用前沿的三维建模技术,为我们呈现了一个全新的知识世界。 随时随地,无论您身处何地,只…

C++STL---stack queue模拟实现

前言 对于这两个容器适配器的模拟实现非常简单,因为stack和queue只是对其他容器的接口进行了包装,在STL中,若我们不指明用哪种容器作为底层实现,栈和队列都默认是又deque作为底层实现的。 也就是说,stack和queue不管是…

js:flex弹性布局

目录 代码&#xff1a; 1、 flex-direction 2、flex-wrap 3、justify-content 4、align-items 5、align-content 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewp…

[论文笔记]AIOS: LLM Agent Operating System

引言 这是一篇有意思的论文AIOS: LLM Agent Operating System&#xff0c;把LLM智能体(代理)看成是操作系统。 基于大语言模型(LLMs)的智能代理的集成和部署过程中存在着许多挑战&#xff0c;其中问题包括代理请求在LLM上的次优调度和资源分配&#xff0c;代理和LLM之间在交互…

智能视频监控平台LntonCVS视频融合共享平台保障露营安全解决方案

在当今社会&#xff0c;都市生活的快节奏和压力使得越来越多的人渴望逃离城市的喧嚣&#xff0c;寻求一种短暂的慢生活体验。他们向往在壮丽的山河之间或宁静的乡村中露营&#xff0c;享受大自然的宁静与美好。随着露营活动的普及&#xff0c;露营地的场景也变得更加丰富多样&a…

干货分享:如何做好采购和供应链管理工作?

简单来说&#xff0c;采购是企业获取所需货物和材料的过程&#xff0c;而供应链管理是将这些货物转化为产品并尽可能高效地分发给客户。 但做好采购和供应链管理的关键是实现采购和供应商的协同管理。为什么这么说呢&#xff1f; 在成本方面&#xff0c;采供协同管理使得企业…

【Vue】单页应用程序介绍

通常基于Vue去开发一整个网站&#xff0c;开发出来的这整个网站应用&#xff0c;我们都会叫做单页应用程序 概念 单页应用程序&#xff1a;SPA【Single Page Application】是指所有的功能都在一个html页面上实现 我们可以将页面共用的部分封装成组件&#xff0c;底下要切换的也…

安卓虚拟屏幕锁屏画面源码分析部分KeyguardPresentation

背景&#xff1a; 在搞虚拟多屏和投屏相关业务时候&#xff0c;发现在锁屏时候一个画面比较特殊&#xff0c;但是明显我们自己也没有给虚拟屏幕和投屏有绘制过这个页面。 具体页面如下&#xff1a; 这个圈中小方框就是虚拟屏幕&#xff0c;在息屏待机时候居然也有个类似锁屏…

【Elasticsearch】IK分词器的下载及使用

安装IK分词器 网址&#xff1a;https://github.com/infinilabs/analysis-ik 3.1.在线安装ik插件&#xff08;较慢,不推荐&#xff09; # 进入容器内部 es为容器名称 docker exec -it es /bin/bash# 在线下载并安装 7.17.21为镜像版本要与之前保持一致 ./bin/elasticsearch-pl…

Docker|了解容器镜像层(1)

引言 容器非常神奇。它们允许简单的进程表现得像虚拟机。在这种优雅的底层是一组模式和实践&#xff0c;最终使一切运作起来。在设计的根本是层。层是存储和分发容器化文件系统内容的基本方式。这种设计既出人意料地简单&#xff0c;同时又非常强大。在今天的帖子[1]中&#xf…

前端 JS 经典:打印对象的 bug

1. 问题 相信这个 console 打印语句的 bug&#xff0c;其实小伙伴们是遇到过的&#xff0c;就是你有一个对象&#xff0c;通过 console&#xff0c;打印一次&#xff0c;然后经过一些处理&#xff0c;再通过 console 打印&#xff0c;发现两次打印的结果是一样的&#xff0c;第…

网络实用技术答案

&#xff08; C &#xff09;不属于计算机网络四要素。A. 计算机系统 B. 传输介质C. 用户 D. 网络协议计算机网络中广域网和局域网的分类是以&#xff08; D &#xff09;来划分的。A. 信息交换方式 B&#xff0e;传输控制方法C. 网络使用习惯 D&#xff0e;网络覆盖范围计算机…