news 2026/4/27 9:39:19

网络协议TCP

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
网络协议TCP

网络编程TCP

TCP的核心特点:面向字节流(UDP是数据报),所有的读写的基本单位都是byte

ServerSocket:专门给服务器使用的,负责连接,不对数据进行操作

Socket:服务器和客户端都可以使用

当服务器启动的时候绑定端口号

因为TCP是有连接的,所以要使用accept去确保连接的开始

Socket要传入服务器的ip和端口号

因为TCP面向的是字节流,所以他没有向UDP数据报的那种sent和review方法,有的是字节流的读取(和之前文件IO很像)

TCPEchoServer

思路

实现TCPEchoServer,首先我们需要知道,所有的代码都是无法直接操作网卡的,一开始,我创建了一个serversocket类型的空变量,然后在构造方法中传入端口号,这个就相当于,我使用serversocket类这个代理人去帮我向操作系统申请一个小窗口,和网卡进行沟通,连接之后,因为serversocket只是连接,无法操作数据,所以就要使用socket来操作,然后在start方法中,首先我使用printf格式打印出来日志,然后因为TCP面向的是字节流,所以我不能向UDP那样使用数据报datagrampacket去进行操作,而是要使用inputstream和outputstream进行操作,这两个本来是需要使用read和write进行操作的,但是为了方便的情况下,我就使用scanner和printwrite进行套壳,然后因为我们这个是服务器,所以要在processconnecition方法中写内层一个死循环反复进行读取,然后当有输入的时候,使用一个string类型的去接收,接收到之后,就要进行处理,因为现在是回显式所以先不管,然后处理完响应只需要发回去就行,这个时候也有一个注意的地方,就是缓冲区,在java中,因为每次直接对网络或者文件进行修改太慢了,所有就会存在一个缓冲区,把你写的全部先存在一个地方,所以他并没有马上就传输出去,必须要等你使用flush把他冲走,他才会真的发送

具体实现

第一步

这一步首先就是创建一个空的serversocket类型的变量,然后在构造方法中初始化的时候传入使用的端口号,说人话就是你没办法直接操作网卡,所以要找serversocket这个代理人帮你和操作系统申请一个窗口,让你能够和网卡进行沟通

第二步

这一步首先就是打印日志,服务器启动,然后因为TCP是有连接的,所以我们需要先处理外层的连接,然后再去处理连接之后的事情,使用socket这个来处理文件的读取注意这个时候因为可能不只一个连接所以我们需要加入一个死循环确保可以支持多个客户端使用

第三步(核心)

这一步就是整个服务器最核心的地方了,首先当确立了连接之后,我们会记录日志,把对方的IP和端口号全部获取到,因为TCP协议是字节流的,所以这个时候就需要使用inputstream和outputstream这两个操作字节流,这里可以使用另外一种写法,每次读取一个数组的长度,读到-1就停止那种,但是就很麻烦,所以我们直接使用scanner和printwrite这两个更方便,只需要对inputstream和outputstream进行套个壳就行,套完壳之后就可以直接使用了。之后就很简单了,只要连接没断开就会一直等,后续的逻辑就是先读取请求,然后计算并返回响应,注意要刷新缓冲区,不然就会出现发不出去的情况,最后打印一下日志就结束。

源码

package NetWork; 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; /** * Created with IntelliJ IDEA. * Description: * User: zhany * Date: 2025-12-15 * Time: 15:07 */ /*tcp协议的特点:有连接,面向字节流,全双工,可靠传输*/ public class TcpServerDemo { //首先,创建一个serversocket的空变量,Serversocket就是专门用来连接的 ServerSocket serverSocket = null; //初始化的同时指定端口号 public TcpServerDemo(int serverPort) throws IOException { serverSocket = new ServerSocket(serverPort); } //start方法 public void start() throws IOException { //首先,这个是服务器,所以需要24小时工作 System.out.println("服务器启动"); while(true){ //前面的serversocket任务已经结束,只负责连接不负责数据的修改,下面登场的是socket Socket clientSocket = serverSocket.accept(); //连接完就要负责处理数据了 Thread thread = new Thread(()->{ processconection(clientSocket); }); thread.start(); } } private void processconection(Socket clientSocket) { //先打印日志 System.out.printf("[%s,%d],客户端上线\n",clientSocket.getInetAddress(),clientSocket.getPort()); try(InputStream inputStream = clientSocket.getInputStream(); OutputStream outputStream = clientSocket.getOutputStream()) { while (true){ //字节流需要使用input和output //1.获取并解析连接 Scanner scanner = new Scanner(inputStream); PrintWriter writer = new PrintWriter(outputStream); if (!scanner.hasNext()){ System.out.printf("[%s,%d],客户端下线\n",clientSocket.getInetAddress(),clientSocket.getPort()); break; } String request = scanner.next(); //计算并返回 String response = process(request); writer.println(response); //刷新缓冲区 writer.flush(); } } catch (IOException e) { e.printStackTrace(); } finally { try { clientSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } private String process(String request) { return request; } public static void main(String[] args) throws IOException { TcpServerDemo tcpServerDemo = new TcpServerDemo(9090); tcpServerDemo.start(); } }

TcpEchoClient

思路

客户端的思路就比较简单,首先在构造方法中,需要初始化一下要去访问的服务器和端口号,然后在start方法中也是比较简单的,因为tcp是字节流的,所以需要直接使用inputstream和outputstream,直接使用套壳的scanner和printwrite会简单一些,不使用就要使用文件io的办法,然后在控制台读取用户的输入,然后发送给服务器,然后接受服务器的请求就可以了,注意这个也是要释放缓冲区的。

具体实现

第一步

Tcp中是提供构造方法让你可以直接输入网址的类似于127.0.0.1,在udp中要调用方法getname才行,这里初始化了要访问的ip和端口号

第二步

核心的start方法,这里就很简单了,因为TCP是字节流,所以他进行的操作也是需要使用inputstream和outputstream来进行操作的,使用scanner和printwrite进行套壳就不需要使用基础的文件io那种复杂的写法,然后只需要在控制台读取用户的输入,然后发送,接收返回值就行了

源码

package NetWork; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; public class TcpClientDemo { private Socket socket; private static final String EXIT_CMD = "exit"; public TcpClientDemo(String serverIP, int serverPort) throws IOException { socket = new Socket(serverIP, serverPort); } public void start() { System.out.println("客户端启动"); System.out.println("输入内容发送到服务器(输入'exit'退出)"); try (InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); Scanner scanner = new Scanner(System.in); Scanner scannerNet = new Scanner(inputStream); PrintWriter writer = new PrintWriter(outputStream)) { while (true) { String request = scanner.nextLine(); if (EXIT_CMD.equalsIgnoreCase(request)) { break; } writer.println(request); writer.flush(); if (scannerNet.hasNextLine()) { String response = scannerNet.nextLine(); System.out.println("服务器响应: " + response); } } } catch (IOException e) { System.err.println("通信异常: " + e.getMessage()); } finally { try { if (socket != null && !socket.isClosed()) { socket.close(); } } catch (IOException e) { System.err.println("关闭socket异常: " + e.getMessage()); } } } public static void main(String[] args) { try { TcpClientDemo tcpClientDemo = new TcpClientDemo("127.0.0.1", 9090); tcpClientDemo.start(); } catch (IOException e) { System.err.println("连接服务器失败: " + e.getMessage()); } } }

上述的代码中,存在一个问题,就是多个客户端去访问的时候,会被卡住,阻塞在

因为当代码执行到确立连接之后,他就会往下走,跳到processconnection里面去,这个时候,后面的线程想要连接就必须等待前面的结束完才可以用

如何解决这个问题?

多线程这个时候就诞生了

只需要在在服务器里面加一个线程

这样就能实现让多线程去实现直接开启分身模式(小心超人上线)

但是每次都创建一个线程和销毁一个线程,开销的很大的,有没有更好的方法,有

线程池方法

在一开始就创建好n个线程,每当一个客户端来了就使用一下线程,这样就能最大限度使用服务器

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 14:49:51

不得了!揭秘专业的固液混合电容厂家背后的行业秘诀!

不得了!揭秘专业的固液混合电容厂家背后的行业秘诀! 行业痛点分析 固液混合电容作为电子领域的关键组件,在众多应用场景中发挥着重要作用,但当前该领域面临着诸多技术挑战。一方面,高温稳定性不佳是一大难题。在高温…

作者头像 李华
网站建设 2026/4/20 16:33:22

CAIE认证上海报考指南:当职业理想遭遇AI现实,如何破局?

早高峰的上海地铁里,刷着招聘软件的人越来越多地看到一个刺眼的要求——“熟悉AI工具者优先”。而在写字楼的格子间里,不少人也正悄悄犯愁:那些听起来很酷的AI技能,到底该怎么系统地去学?又怎么向老板证明自己真的会了…

作者头像 李华
网站建设 2026/4/25 9:19:47

uniApp的学习与思考

移动端开发 IOS 安卓 web 小程序等缺点&#xff1a; 一对多&#xff1a;性能差 上架可能会有问题 中小公司 优点&#xff1a;一套代码可以发布到 Ios 安卓 web 小程序 虽然要走条件编译Hbudder开发<ifedf h5> <view> h5展示<ennif > <view> 小程序展示…

作者头像 李华
网站建设 2026/4/23 10:38:13

基于STM32的温度PID控制系统实现

一、系统架构设计 1.1 核心模块选型模块推荐型号关键参数温度传感器DS18B2012位分辨率&#xff0c;0.5℃精度执行机构TEC1-12706最大温差60℃&#xff0c;电流6A电压基准REF30303.0V0.05%精度电流检测ACS712ELC-055A量程&#xff0c;1.5%误差 二、硬件接口实现 2.1 传感器接口电…

作者头像 李华
网站建设 2026/4/25 21:10:28

君耀压敏电阻25D系列的高性能过压保护解决方案

君耀压敏电阻25D系列是君耀&#xff08;Brightking&#xff09;推出的高性能压敏电阻产品&#xff0c;广泛应用于电子电路的过压保护。该系列产品以其快速响应、高浪涌电流承受能力以及广泛的电压范围而备受市场青睐。可以说&#xff0c;君耀压敏电阻25D系列是您的高性能过压保…

作者头像 李华