news 2026/5/8 21:11:34

四十三、网络编程(下)——TCP 编程与 HTTP 入门

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
四十三、网络编程(下)——TCP 编程与 HTTP 入门

😫痛点引入:UDP 发出去就不管了,万一丢包怎么办?文件上传必须每字节都不能少!
TCP 协议应运而生——面向连接、可靠传输、三次握手确认!☎️
下篇手写 TCP 客户端-服务端、文件上传、多线程并发服务器,最后揭秘网页背后的 HTTP 协议!


一、TCP 协议——面向连接的「电话」☎️

1.1 回顾:UDP vs TCP

对比项UDP(上篇)TCP(本篇)
连接性无连接 ❌面向连接 ✅
可靠性不可靠(可能丢包)可靠(确认机制)✅
效率较低
类比发短信、寄信 📮打电话 ☎️
区分发送端 / 接收端客户端 / 服务端

1.2 TCP 三次握手(面试必问!📝)

客户端 服务端 | | | ① SYN (我想连接) | | -----------------------------> | | | | ② SYN+ACK (可以,我也准备好了) | | <----------------------------- | | | | ③ ACK (收到,开始传数据!) | | -----------------------------> | | | ✅ 三次握手完成,连接建立!

💡为什么是三次?两次可能死锁(服务端以为连上了,客户端其实没收到确认),三次才能保证双方都说清楚!


二、TCP 核心类 🔧

2.1 两个套接字

类名角色作用获取方式
Socket客户端套接字连接服务端、发送/接收数据new Socket(ip, port)
ServerSocket服务端套接字监听端口、接收客户端连接new ServerSocket(port)

2.2 核心方法速查

Socket 常用方法

方法功能
getInputStream()获取输入流,读取对方发来的数据 📥
getOutputStream()获取输出流,向对方发送数据 📤
shutdownOutput()关闭输出流(发送结束标记)⚠️
close()关闭连接

ServerSocket 常用方法

方法功能
accept()接收客户端连接,返回客户端 Socket(阻塞

2.3 数据交互方式

客户端发送 → 服务端读取: 客户端:getOutputStream().write(...) 服务端:getInputStream().read(...) 客户端读取 ← 服务端发送: 客户端:getInputStream().read(...) 服务端:getOutputStream().write(...)

三、TCP 基本通信 💬

3.1 客户端代码

importjava.net.Socket;importjava.io.OutputStream;publicclassTCP_Client{publicstaticvoidmain(String[]args)throwsException{// ⚠️ new Socket() 就会触发三次握手!// 成功说明连接建立 ✅,失败抛出异常Sockets=newSocket("192.168.26.23",8888);// 发送消息给服务端OutputStreamos=s.getOutputStream();os.write("江总你好!".getBytes());s.close();System.out.println("客户端发送完成!☎️");}}

3.2 服务端代码

importjava.net.ServerSocket;importjava.net.Socket;importjava.io.InputStream;publicclassTCP_Server{publicstaticvoidmain(String[]args)throwsException{System.out.println("服务端启动,等待连接...📞");// 1. 创建服务端,指定端口ServerSocketss=newServerSocket(8888);// 2. accept() 阻塞等待客户端连接Socketclient=ss.accept();System.out.println("客户端已连接:"+client.getInetAddress());// 3. 读取客户端消息InputStreamis=client.getInputStream();byte[]buf=newbyte[1024];intlen=is.read(buf);// read() 阻塞,直到读完Stringmsg=newString(buf,0,len);System.out.println("收到:"+msg);client.close();}}

3.3 ⚠️ TCP 编程注意点

  1. 服务端必须先启动!否则客户端连接失败
  2. new Socket()触发三次握手,服务端没启动就抛异常
  3. accept()阻塞,直到有客户端连接
  4. read()阻塞,直到读到数据或对方关闭流

四、TCP 双向通信 💬

4.1 服务端(收消息 + 回复)

importjava.net.*;importjava.io.*;importjava.util.Scanner;publicclassTCP_ServerPro{publicstaticvoidmain(String[]args)throwsException{ServerSocketss=newServerSocket(8888);Scannersc=newScanner(System.in);System.out.println("服务端启动...📞");Socketclient=ss.accept();System.out.println("客户端连接:"+client.getInetAddress());while(true){// 1. 读取客户端消息InputStreamis=client.getInputStream();byte[]buf=newbyte[1024];intlen=is.read(buf);Stringmsg=newString(buf,0,len);System.out.println("客户端:"+msg);// 2. 回复客户端System.out.print("请输入回复:");Stringreply=sc.next();OutputStreamos=client.getOutputStream();os.write(reply.getBytes());}}}

4.2 客户端(发消息 + 收回复)

importjava.net.*;importjava.io.*;importjava.util.Scanner;publicclassTCP_ClientPro{publicstaticvoidmain(String[]args)throwsException{Sockets=newSocket("192.168.26.23",8888);Scannersc=newScanner(System.in);while(true){// 1. 发送消息System.out.print("请输入消息:");Stringmsg=sc.next();OutputStreamos=s.getOutputStream();os.write(msg.getBytes());// 2. 接收服务端回复InputStreamis=s.getInputStream();byte[]buf=newbyte[1024];intlen=is.read(buf);System.out.println("服务端回复:"+newString(buf,0,len));}}}

五、TCP 文件上传 📤

5.1 需求

客户端上传图片到服务端,服务端保存后给客户端响应。

5.2 客户端(读文件 + 上传)

importjava.net.*;importjava.io.*;publicclassTCP_FileClient{publicstaticvoidmain(String[]args)throwsException{Sockets=newSocket("127.0.0.1",9999);// 1. 读取本地文件FileInputStreamfis=newFileInputStream("D:/1.jpg");OutputStreamos=s.getOutputStream();// 2. 循环写出(上传)文件数据byte[]buf=newbyte[1024];intlen;while((len=fis.read(buf))!=-1){os.write(buf,0,len);}// ⚠️ 关键!告诉服务端"我传完了"s.shutdownOutput();fis.close();// 3. 读取服务端响应InputStreamis=s.getInputStream();byte[]respBuf=newbyte[1024];intrespLen=is.read(respBuf);System.out.println("服务端:"+newString(respBuf,0,respLen));s.close();}}

5.3 服务端(收文件 + 保存 + 响应)

importjava.net.*;importjava.io.*;importjava.util.Random;publicclassTCP_FileServer{publicstaticvoidmain(String[]args)throwsException{ServerSocketss=newServerSocket(9999);System.out.println("文件服务器启动...📤");Socketclient=ss.accept();System.out.println("客户端上传:"+client.getInetAddress());// 1. 读取客户端上传数据InputStreamis=client.getInputStream();// 2. 生成随机文件名(防止覆盖)Randomr=newRandom();FileOutputStreamfos=newFileOutputStream("D:/upload/"+r.nextInt(Integer.MAX_VALUE)+".jpg");byte[]buf=newbyte[1024];intlen;while((len=is.read(buf))!=-1){fos.write(buf,0,len);// 保存到磁盘}fos.close();// 3. 给客户端响应OutputStreamos=client.getOutputStream();os.write("上传成功!✅".getBytes());client.close();}}

5.4 ⚠️ shutdownOutput() —— 文件上传的灵魂

不用 shutdownOutput(): 服务端 read() 永远阻塞,不知道客户端传完了 😱 用了 shutdownOutput(): 客户端调用后,发送一个"结束标记" 服务端 read() 收到 -1,跳出循环 ✅

一句话shutdownOutput()= 告诉对方"我说完了,你可以处理了"!


六、TCP 多线程并发服务器 🧵

6.1 为什么需要多线程?

单线程服务器: 客户端A 连接 → 服务器处理A → 处理完才能处理B → 客户端B 等着,体验极差 ❌ 多线程服务器: 客户端A 连接 → 开线程1 处理A 客户端B 连接 → 开线程2 处理B → 同时处理,互不影响 ✅

6.2 多线程服务端代码

importjava.net.*;importjava.io.*;importjava.util.Random;publicclassTCP_MultiThreadServer{publicstaticvoidmain(String[]args)throwsException{ServerSocketss=newServerSocket(9999);System.out.println("多线程服务器启动...🧵");while(true){Socketclient=ss.accept();// 等待客户端System.out.println("新客户端:"+client.getInetAddress());// 为每个客户端开启独立线程!newThread(()->{try{// 接收文件InputStreamis=client.getInputStream();Randomr=newRandom();FileOutputStreamfos=newFileOutputStream("D:/upload/"+r.nextInt(Integer.MAX_VALUE)+".jpg");byte[]buf=newbyte[1024];intlen;while((len=is.read(buf))!=-1){fos.write(buf,0,len);}fos.close();// 响应客户端OutputStreamos=client.getOutputStream();os.write("上传成功!✅".getBytes());client.close();System.out.println("客户端上传完成!");}catch(Exceptione){e.printStackTrace();}}).start();// 启动线程!}}}

6.3 启动多个客户端测试

publicclassTCP_MultiClientTest{publicstaticvoidmain(String[]args){// 同时启动 3 个客户端,并发上传for(inti=0;i<3;i++){newThread(()->{try{Sockets=newSocket("127.0.0.1",9999);FileInputStreamfis=newFileInputStream("D:/1.jpg");OutputStreamos=s.getOutputStream();byte[]buf=newbyte[1024];intlen;while((len=fis.read(buf))!=-1){os.write(buf,0,len);}fis.close();s.shutdownOutput();// 接收响应InputStreamis=s.getInputStream();byte[]resp=newbyte[1024];intrespLen=is.read(resp);System.out.println(Thread.currentThread().getName()+":"+newString(resp,0,respLen));s.close();}catch(Exceptione){e.printStackTrace();}}).start();}}}

💡 多线程上传优势

  • 多个客户端同时上传
  • 每个客户端独占线程,互不干扰
  • 服务端持续运行,不用重启

七、HTTP 协议入门——网页背后的原理 🌐

7.1 HTTP 是什么

HTTP(HyperText Transfer Protocol):超文本传输协议,应用层最常用的协议。

7.2 HTTP 请求格式

GET /index.html HTTP/1.1 ← 请求行(方法 + 路径 + 版本) Host: www.example.com ← 请求头 User-Agent: Mozilla/5.0 ← 空行(必须!) [请求体] ← GET 请求通常没有

7.3 HTTP 响应格式

HTTP/1.1 200 OK ← 状态行(版本 + 状态码 + 消息) Content-Type: text/html ← 响应头 Content-Length: 1234 ← 空行(必须!) <html>...</html> ← 响应体(网页内容)

7.4 常见状态码

状态码含义
200请求成功 ✅
301永久重定向
302临时重定向
404资源未找到 ❌
500服务器内部错误 ⚠️

7.5 💡 TCP 与 HTTP 的关系

TCP 是传输层协议 → 负责可靠传输数据 ☎️ ↓ HTTP 是应用层协议 → 定义数据格式(请求头/响应头)🌐 ↓ HTTP 底层使用 TCP 传输!

一句话:HTTP = 带格式的 TCP!


本篇总结 📝

  1. TCP 协议☎️:面向连接、可靠传输、三次握手确认
  2. 三次握手📝:SYN → SYN+ACK → ACK,保证双方都确认连接
  3. Socket vs ServerSocket🔧:客户端new Socket(ip,port)、服务端new ServerSocket(port)+accept()
  4. 数据交互📥📤:getInputStream()读、getOutputStream()
  5. TCP 双向通信💬:客户端发→服务端收→服务端回→客户端收
  6. 文件上传📤:客户端读文件写服务端 +shutdownOutput()发送结束标记
  7. 多线程服务器🧵:while(true) { accept(); new Thread(...).start(); }支持并发
  8. HTTP 协议🌐:应用层协议,定义请求/响应格式,底层用 TCP 传输

作者:书源丶
发布平台:CSDN

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

16QAM调制与LO相位噪声的工程挑战与解决方案

1. 16QAM调制与LO相位噪声的工程挑战在TD-SCDMA等现代无线通信系统中&#xff0c;16QAM&#xff08;16进制正交幅度调制&#xff09;因其高频谱效率被广泛采用。这种调制方式将每4个比特映射为一个复数符号&#xff0c;形成包含12个相位点的星座图。与QPSK相比&#xff0c;16QA…

作者头像 李华
网站建设 2026/5/8 21:09:51

YOLO标注程序

使用YOLO,其中不可逾越的一步是要对原图进行标注,为了方便,自己用python编写了标注小程序,经过验证,也是非常好用的。贡献出分享出来,以供同行切磋。 以下是源代码,完全共享,无需付费。 import os import tkinter as tk from tkinter import filedialog,ttk,messageb…

作者头像 李华
网站建设 2026/5/8 21:07:44

别再只会用默认样式了!MATLAB R2023b绘图配色与线型搭配实战指南

MATLAB R2023b科研绘图美学&#xff1a;从配色理论到学术图表实战 科研图表的第一印象往往决定了读者对研究成果的信任度。当审稿人打开论文&#xff0c;或是听众看到演示文稿时&#xff0c;一张配色混乱、线型随意的图表可能瞬间降低内容的专业可信度。MATLAB作为工程与科研领…

作者头像 李华