
简介这份资源是华中科技大学计算机科学与技术专业的计算机网络课程实验报告面向正在学习计算机网络、需要完成Socket编程与网络组建实验的高校学生。报告以docx文档形式呈现压缩包内共1个文件大小约3.67MB内容结构完整包含实验目的、要求、内容、过程与体会等标准章节。报告涵盖两大部分一是基于Java Socket的E-Mail编程实验涉及TCP/UDP Socket分类、客户端-服务器架构、SMTP与POP3等邮件协议并给出需求分析、界面设计、写信与收信的实现过程二是网络组建与实施实验包含组网、路由配置、VLAN划分及访问控制配置四个子实验涉及网络拓扑结构、路由器与交换机等设备配置及网络测试方法。目前已有427人学习适合作为课程实验参考与期末复习资料帮助读者理解网络通信编程与组网配置的关键步骤。1. 从一份 2013 年的华科实验报告说起Java Socket 手写邮件客户端到底能跑通什么翻到这份《华科-计算机网络实验报告-Java_Socket编程-网络组建实验.docx》的时候我第一反应是这不是那种交完就删的课程作业而是一份把应用层协议从零拆到字节流的完整记录。它用 Java 的Socket类直接怼 SMTP 和 POP3 服务器不借助JavaMail这类现成组件硬生生把一封邮件的发送、接收、下载、删除全流程走了一遍。对正在啃 socket 网络编程、准备 java 面试题里“TCP 三次握手怎么落到代码”这类问题的同学来说这份报告的价值不在于界面多漂亮而在于它把EHLO、AUTH LOGIN、MAIL FROM、RCPT TO、DATA这些命令和服务器返回码一行行打印出来让你看见协议是怎么呼吸的。它适合两类人一是刚学完计算机网络、想找个能跑通的 demo 把理论焊死在代码上的学生二是需要快速回顾 Java 原生 Socket 操作、不想被框架封装遮住眼睛的开发者。下面我就按“这份资源是什么、怎么复现、坑在哪”的顺序把它拆开讲透。2. 把 SMTP 会话拆成命令行SendAction 里每一行代码在跟服务器说什么2.1 为什么不用 JavaMail 而坚持裸写 Socket这份报告在实验要求里写得很死“必须基于 Socket 编程不能直接借用任何现成的组件。” 这条约束恰恰是它最值得看的地方。JavaMail把Session、Transport、Store封装得太好好到你写完Transport.send(message)就结束了根本不知道背后发了什么。而裸写 Socket 意味着你要自己拼邮件报文、自己处理 Base64 编码、自己读服务器应答。常见做法是先用telnet连一下邮件服务器的 25 端口手动敲一遍EHLO、AUTH LOGIN看服务器怎么回再把这一串交互翻译成 Java 代码。报告里SendAction函数就是这么干的它把发件人、收件人、主题、正文拼成一个字符串然后通过PrintWriter一行行推给服务器。这种写法在 2024 年看确实原始但对于理解 SMTP 是“基于文本行的请求-响应协议”这件事没有比它更直接的了。2.2 SendAction 的完整调用链与参数含义先看类里的数据结构这是后面所有操作的输入源public class SendFrame extends JInternalFrame { private JTextField txt_to; // 收件人地址输入框 private JTextField txt_subject; // 主题输入框 private JTextArea textArea; // 正文输入区 private String pusernameadd; // 当前用户完整邮件地址如 xxx163.com private String ppasswd; // 邮箱密码或授权码 private String psn_s_smtp; // SMTP 服务器地址如 smtp.163.com private String pusername1; // 用户名不含 后缀 }这些字段在构造函数SendFrame里从登录界面传进来赋值后一直挂在对象上。当用户点击 Send 按钮btnNewButton.addActionListener触发调用SendAction(txt_to.getText(), textArea.getText(), txt_subject.getText())。注意参数顺序收件人、正文、主题——这个顺序和界面上从上到下的排列不一致写代码时如果按界面顺序传参主题和正文就会互换这是第一个容易翻车的地方。SendAction内部的核心逻辑分四步。第一步拼报文mailContent From: from \n To: to \n Subject: subject1 \n Constent: constent1 \n;这里有个明显的笔误Constent应该是Content但 SMTP 协议本身不校验头部字段名服务器只认From、To、Subject这些标准字段Constent会被当作自定义头忽略掉正文实际上是通过后面的DATA段单独发送的。所以这个拼写错误不影响功能但会让你在抓包时困惑一下。第二步建立连接并读取欢迎语String hostName InetAddress.getLocalHost().getHostName(); Socket s new Socket(mailServer, 25); BufferedReader inFromServer new BufferedReader( new InputStreamReader(s.getInputStream())); PrintWriter outToServer new PrintWriter(s.getOutputStream(), true); response inFromServer.readLine(); System.out.print(MailServer: response \n);new Socket(mailServer, 25)这行代码背后是 TCP 三次握手连上之后服务器会主动推一行220开头的欢迎语。PrintWriter的第二个参数true表示自动 flush少了它你会发现在readLine()那里卡死——因为数据还在缓冲区里没发出去。第三步身份验证这是最容易出问题的地方BASE64Encoder encoder new BASE64Encoder(); String encodedUser encoder.encode(pusername1.getBytes()); String encodedPwd encoder.encode(ppasswd.getBytes()); outToServer.println(EHLO hostName); for (int i 0; i 5; i) { response inFromServer.readLine(); System.out.print(MailServer: response \n); } outToServer.println(AUTH LOGIN ); response inFromServer.readLine(); outToServer.println(encodedUser); response inFromServer.readLine(); outToServer.println(encodedPwd); response inFromServer.readLine();EHLO之后服务器会返回多行应答报告里硬编码读 5 行这个数字因服务器而异。163 邮箱通常返回 5 行左右但 Gmail 可能更多。如果读少了后面的AUTH LOGIN应答就会错位读多了readLine()会阻塞。稳妥的做法是循环读到某行以空格开头多行应答的续行标志或者直接判断返回码。AUTH LOGIN之后服务器分别要用户名和密码的 Base64 编码注意这里用的是pusername1不含 的用户名而不是完整地址用错了会返回535认证失败。第四步发信并断开outToServer.println(MAIL FROM: from ); response inFromServer.readLine(); outToServer.println(RCPT TO: to ); response inFromServer.readLine(); outToServer.println(DATA); response inFromServer.readLine(); outToServer.println(mailContent); outToServer.println(.); response inFromServer.readLine(); s.close();MAIL FROM和RCPT TO后面必须跟尖括号包裹的地址这是 RFC 5321 的规定。DATA之后服务器返回354然后你发送正文最后用一个单独的点号.表示结束。报告里outToServer.println(mailContent)出现了两次这是重复发送正文的 bug会导致邮件内容翻倍。正确做法是只发一次然后紧跟一个.。2.3 参数怎么改、失败时看什么如果你要拿这份代码去连自己的邮箱需要改三个地方psn_s_smtp改成你的 SMTP 服务器地址163 是smtp.163.comQQ 是smtp.qq.compusernameadd改成完整邮件地址ppasswd改成授权码而不是登录密码。现在主流邮箱都要求用授权码直接用密码会返回535。端口方面25 端口在很多网络环境下被运营商封了可以试 465SSL或 587STARTTLS但这份代码没有实现 SSL 层所以只能跑 25 端口这是它的时代局限。失败时优先看控制台打印的MailServer:那几行。220是连接成功250是命令接受334是等待 Base64 输入235是认证成功354是开始发正文221是断开。如果卡在某个readLine()不动八成是上一条命令发出去后服务器没给预期响应用telnet手动复现一遍就能定位。3. POP3 收信与邮件列表渲染GetMail 怎么把服务器邮件拉进 JTable3.1 POP3 的三种状态与 getsubmaillist 的取头逻辑收信部分由GetMail和POP3Client两个类协作完成。GetMail负责界面和邮件列表展示POP3Client负责跟服务器对话。POP3 协议分三个阶段授权USER/PASS、事务STAT、LIST、RETR、DELE、更新QUIT。报告里的getsubmaillist()函数对应事务阶段的TOP命令只拉取邮件头信息public void getsubmaillist() throws Exception { POP3Client pop3 new POP3Client(get_server, get_username, get_passwd); pop3.connect(); int mailCount pop3.getMailCount(); submaillist new String[mailCount]; for (int i 1; i mailCount; i) { String header pop3.getMailHeader(i); submaillist[i - 1] header; } pop3.disconnect(); }getMailCount()内部发的是STAT命令服务器返回OK 3 12345表示有 3 封邮件、总大小 12345 字节。getMailHeader(i)发的是TOP i 0只取第 i 封邮件的头部不取正文。这样做的目的是快速列出收件箱避免一次性下载所有邮件正文导致界面卡死。报告里maillist是一个String[20][3]的二维数组分别存标题、发件人、时间从头部信息里解析出来填进去。3.2 JTable 的数据绑定与 Show 按钮的事件传递GetMail的构造函数里getsubmaillist()和getmaillist()被依次调用然后把maillist数组直接塞给JTableObject[] columnTitle {Title, From, Time}; table new JTable(maillist, columnTitle); table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); table.setBounds(14, 44, 804, 366); contentPane.add(table.getTableHeader()); contentPane.add(table);JTable用二维数组构造时第一维是行第二维是列列的顺序必须和columnTitle一一对应。报告里maillist[a][2]存的是时间maillist[a][1]存的是发件人maillist[a][0]存的是标题但在Show按钮的事件里传参顺序是new ShowMail(maillist[a][2], maillist[a][1], maillist[a][0], ...)也就是时间、发件人、标题。如果ShowMail构造函数按标题、发件人、时间的顺序接收这里就会错位。这是第二个容易翻车的地方建议在传参前先打印一下数组内容确认。Show按钮的完整逻辑btnShow.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int[] selected table.getSelectedRows(); int a selected[0]; DESKTOP_PANE.add(new ShowMail( maillist[a][2], maillist[a][1], maillist[a][0], getmailcontent(a 1), DESKTOP_PANE, get_usernamelong, get_passwd, get_username, get_smtp, get_server)); } });getSelectedRows()返回选中行的索引数组selected[0]取第一行。getmailcontent(a 1)发的是RETR a1把第 a1 封邮件的完整内容拉下来。注意 POP3 的邮件编号从 1 开始而数组索引从 0 开始所以这里要加 1。3.3 DownloadAll 与 DownloadDelete 的差异报告里还有两个按钮DownloadAll和DownloadDelete。前者循环调用RETR把所有邮件保存到本地文件后者在保存之后额外发一个DELE命令标记删除最后QUIT时服务器才真正删除。DELE只是打标记如果在QUIT之前断开连接删除不会生效。这个机制是 POP3 的“后悔药”但报告里没有实现异常回滚如果保存文件时抛了IOExceptionDELE已经发出去了邮件就真没了。稳妥的做法是先全部RETR并写文件成功再统一发DELE。4. 网络组建实验的配置逻辑从 VLAN 划分到访问控制列表4.1 实验环境与拓扑搭建的先后顺序报告的第二部分“网络组建与实施”覆盖了四个子实验组网、路由配置、VLAN 划分、访问控制配置。实验环境通常是 Cisco Packet Tracer 或真实交换机路由器。组网实验要求把 PC、交换机、路由器按指定拓扑连起来配置 IP 地址和子网掩码验证同网段互通。路由配置实验要求配置静态路由或 RIP让不同网段互通。VLAN 划分实验要求在同一台交换机上创建多个 VLAN把端口划分进去验证广播域隔离。访问控制实验要求用 ACL 限制特定流量。这四个实验有严格的依赖顺序先组网通物理层和数据链路层再配路由通网络层再划 VLAN 隔离广播域最后用 ACL 做安全策略。如果顺序反了比如先配 ACL 再划 VLANACL 绑定的接口可能因为 VLAN 变更而失效。报告里 2.4.2 到 2.4.5 的节次安排就是这个顺序照着做不会乱。4.2 VLAN 划分的关键命令与验证方法以 Cisco 交换机为例创建 VLAN 并划分端口的典型配置Switch enable Switch# configure terminal Switch(config)# vlan 10 Switch(config-vlan)# name IT Switch(config-vlan)# exit Switch(config)# vlan 20 Switch(config-vlan)# name HR Switch(config-vlan)# exit Switch(config)# interface fastEthernet 0/1 Switch(config-if)# switchport mode access Switch(config-if)# switchport access vlan 10 Switch(config-if)# exit Switch(config)# interface fastEthernet 0/2 Switch(config-if)# switchport mode access Switch(config-if)# switchport access vlan 20 Switch(config-if)# end Switch# show vlan briefswitchport mode access把端口设为接入模式switchport access vlan 10把它划进 VLAN 10。验证时用show vlan brief看端口归属然后在同一 VLAN 的两台 PC 之间 ping 通不同 VLAN 的 PC 之间 ping 不通。如果不同 VLAN 能 ping 通说明端口没划对或者交换机之间跑了 VTP 把 VLAN 配置同步乱了。4.3 访问控制列表的匹配顺序与常见误配ACL 的规则是从上往下匹配一旦匹配就执行动作不再往下看。所以拒绝规则要放在允许规则前面。一个典型的扩展 ACLSwitch(config)# access-list 100 deny tcp 192.168.10.0 0.0.0.255 192.168.20.0 0.0.0.255 eq 80 Switch(config)# access-list 100 permit ip any any Switch(config)# interface fastEthernet 0/24 Switch(config-if)# ip access-group 100 indeny tcp拒绝 VLAN 10 访问 VLAN 20 的 80 端口permit ip any any放行其他所有流量。最后一行ip access-group 100 in把 ACL 应用到接口的入方向。常见误配是忘了最后的permit导致所有流量被隐式拒绝整个网络不通。另一个坑是 ACL 应用方向搞反in是进入接口的流量out是离开接口的流量配错了规则不生效。5. 避坑与排查这份 2013 年的代码放到今天跑要注意什么5.1 现象连接 25 端口超时控制台没有任何输出原因现在绝大多数云服务器和家庭宽带都封了 25 端口的出站流量防止垃圾邮件。报告写于 2013 年当时 25 端口还能随便用。解决换用 465 或 587 端口但这份代码没有实现 SSL/TLS直接改端口号会连上但无法完成AUTH LOGIN。要么补上SSLSocketFactory的代码要么用本地搭建的邮件服务器如 hMailServer在局域网内测试。5.2 现象AUTH LOGIN之后返回535 Authentication failed原因用了邮箱登录密码而不是授权码。163、QQ、Gmail 从 2022 年起全面要求第三方客户端使用授权码。解决登录网页邮箱在设置里开启 SMTP/POP3 服务并生成授权码把ppasswd换成授权码。注意授权码是 16 位字符串不要带空格。5.3 现象EHLO之后readLine()阻塞程序卡死原因报告里硬编码读 5 行应答但不同邮件服务器返回的行数不同。163 可能返回 5 行QQ 返回 6 行Gmail 返回 4 行。读少了后面的命令错位读多了阻塞。解决改成循环读取判断每行是否以空格开头多行应答的续行或者读到返回码后跟空格的行停止。示例String line; while ((line inFromServer.readLine()) ! null) { System.out.println(MailServer: line); if (line.length() 4 line.charAt(3) ) { break; } }5.4 现象邮件发送成功但正文为空或重复原因报告里outToServer.println(mailContent)写了两次导致正文重复。另外mailContent里用了Constent而不是Content虽然不影响发送但会让头部多一个无效字段。解决删掉重复的那行println把Constent改成Content。正文应该只在DATA之后发送一次然后紧跟一个单独的点号。5.5 现象BASE64Encoder编译报错提示找不到符号原因sun.misc.BASE64Encoder是 JDK 内部类从 JDK 9 开始被移除JDK 11 之后完全不可用。解决换成java.util.Base64String encodedUser Base64.getEncoder().encodeToString(pusername1.getBytes()); String encodedPwd Base64.getEncoder().encodeToString(ppasswd.getBytes());注意Base64.getEncoder()默认不加换行而sun.misc版本每 76 个字符加一个换行。SMTP 的AUTH LOGIN对换行不敏感但如果你发现认证失败可以试Base64.getMimeEncoder()。6. 进阶玩法把这份报告改成可配置的邮件客户端并验证协议交互如果你已经跑通了基本流程下一步可以把硬编码的参数抽成配置文件让程序支持多邮箱切换。我一般会在项目根目录放一个mail.propertiessmtp.serversmtp.163.com smtp.port25 pop3.serverpop3.163.com pop3.port110 usernameyourname passwordyour_auth_code fromyourname163.com然后在 Java 里用Properties加载Properties props new Properties(); try (InputStream in new FileInputStream(mail.properties)) { props.load(in); } String smtpServer props.getProperty(smtp.server); int smtpPort Integer.parseInt(props.getProperty(smtp.port));这样换邮箱只需要改配置文件不用重新编译。更进一步可以把SendAction和POP3Client里的System.out.print换成日志框架把每次会话的请求和响应写到文件里方便事后排查。我习惯在readLine()之后加一行logger.debug(S: response)在println()之前加一行logger.debug(C: command)这样抓出来的日志和 Wireshark 抓包能对上。验证协议交互是否正确的终极方法是同时开 Wireshark 抓包过滤tcp.port 25看 Java 程序发出的每一行和服务器返回的每一行是否和日志一致。如果日志里有但抓包没有说明PrintWriter没 flush如果抓包有但日志没有说明readLine()读到了空行或者阻塞了。这个对照过程能帮你把 Socket 编程里“发送”和“接收”的边界彻底搞清楚。从那以后我每次写 Socket 相关的代码都会强制走一遍“先 telnet 手动敲、再写代码、最后抓包对照”的流程少一步都可能被玄学问题卡半天。希望这份拆解能帮到你。本文还有配套的精品资源点击获取