一,网络编程基础
网络模型
-
OSI 七层模型
层级 名称 功能 例子 7 应用层 用户接口,应用程序访问网络服务 HTTP、FTP、SMTP 6 表示层 数据格式转换、加密解密 JPEG、ASCII、加密 5 会话层 建立、管理、终止会话 RPC、NetBIOS 4 传输层 端到端连接,可靠传输 TCP、UDP 3 网络层 逻辑寻址,路由选择 IP、ICMP、路由器 2 数据链路层 物理寻址,帧传输 MAC地址、交换机 1 物理层 物理介质,比特流传输 网线、光纤、集线器 -
TCP/IP 四层模型
层级 名称 对应OSI层 协议 4 应用层 应用层+表示层+会话层 HTTP、FTP、DNS、SMTP 3 传输层 传输层 TCP、UDP 2 网络层 网络层 IP、ICMP、ARP 1 网络接口层 数据链路层+物理层 Ethernet、WiFi -
Java 主要工作在传输层(TCP/UDP)和应用层
核心包
import java.net.*; // 主要网络类
import java.io.*; // IO流支持
网络编程就是在网络通信协议下,不同计算机上运行的程序,进行的数据传送,本质就是不同计算机之间通过网络进行数据传送。
常见的软件架构:
-
B/S 架构:Browser/Server,即浏览器 / 服务器的架构
只需要一个浏览器,用户通过不同的网址,客户访问不同的服务器。
优点:
- 不需要开发客户端,只需要页面+服务的
- 用户不需要下载,打开浏览器即可使用
缺点:如果应用过大,用户体验会受到影响
-
C/S 架构:Client/Server,即客户端 / 服务的架构
在用户本地需要下载并安装客户端程序,在远程有一个服务器端程序。
优点:画面可做的非常精美,用户体验很好
缺点: 需要开发客户端,也需要开发服务的,维护开发部署很麻烦,用户需要下载和更新的时候很麻烦。
网络编程三要素:ip,端口,协议
常用框架
- Netty - 高性能NIO框架
- Apache HttpClient - HTTP客户端库
- OkHttp - 现代HTTP客户端
- Spring WebFlux - 响应式Web框架
二,IP地址核心类
2.1 InetAddress基本使用
import java.net.InetAddress;
// 获取本地主机
InetAddress local = InetAddress.getLocalHost();
System.out.println("本地主机: " + local);
// 输出: 本地主机: DESKTOP-ABC/192.168.1.100
// 通过域名获取
InetAddress google = InetAddress.getByName("www.google.com");
System.out.println("Google IP: " + google.getHostAddress());
// 输出: Google IP: 142.250.74.68
// 获取所有IP(可能有多个)
InetAddress[] allIps = InetAddress.getAllByName("www.google.com");
for (InetAddress ip : allIps) {
System.out.println(ip.getHostAddress());
}
2.2 InetAddress常用方法
InetAddress address = InetAddress.getByName("192.168.1.1");
// 基本信息
String ip = address.getHostAddress(); // "192.168.1.1"
String hostname = address.getHostName(); // 主机名或IP字符串
String canonicalName = address.getCanonicalHostName(); // 规范主机名
// 类型判断
boolean isLoopback = address.isLoopbackAddress(); // 是否是回环地址(127.x.x.x)
boolean isSiteLocal = address.isSiteLocalAddress(); // 是否是内网地址(192.168.x.x, 10.x.x.x, 172.16-31.x.x)
boolean isLinkLocal = address.isLinkLocalAddress(); // 是否是链路本地地址(169.254.x.x)
boolean isAnyLocal = address.isAnyLocalAddress(); // 通配地址(0.0.0.0)
boolean isMulticast = address.isMulticastAddress(); // 是否是组播地址
// 可达性测试(ping)
boolean reachable = address.isReachable(5000); // 5秒超时
2.3 Inet4Address - IPv4专门类
// 实际上你很少需要直接创建它
Inet4Address ipv4 = (Inet4Address) InetAddress.getByName("192.168.1.1");
// 判断是否是IPv4
if (address instanceof Inet4Address) {
System.out.println("这是IPv4地址");
}
2.4 Inet6Address - IPv6专门类
Inet6Address ipv6 = (Inet6Address) InetAddress.getByName("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
// IPv6特有方法
byte[] ipv6Bytes = ipv6.getAddress(); // 16字节数组
boolean isIPv4Compatible = ipv6.isIPv4CompatibleAddress(); // 是否IPv4兼容
String scopeId = ipv6.getScopedInterface().getName(); // 作用域ID
2.5 InetSocketAddress - IP+端口组合
用于 Socket 编程,包含 IP 地址和端口号
// 创建方式
InetSocketAddress socketAddr1 = new InetSocketAddress("localhost", 8080);
InetSocketAddress socketAddr2 = new InetSocketAddress(InetAddress.getLocalHost(), 8080);
InetSocketAddress socketAddr3 = new InetSocketAddress(8080); // 通配地址: 0.0.0.0:8080
// 获取信息
String hostname = socketAddr1.getHostName(); // 解析主机名
String hostString = socketAddr1.getHostString(); // 原始字符串
InetAddress address = socketAddr1.getAddress(); // InetAddress对象
int port = socketAddr1.getPort(); // 端口号
boolean unresolved = socketAddr1.isUnresolved(); // 是否未解析
// 用在Socket中
ServerSocket server = new ServerSocket();
server.bind(socketAddr1); // 绑定到指定地址和端口
2.6 NetworkInterface - 网络接口类
代表网卡、网络接口
import java.net.NetworkInterface;
// 获取所有网络接口
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface ni = interfaces.nextElement();
System.out.println("接口名称: " + ni.getName()); // eth0, wlan0
System.out.println("显示名称: " + ni.getDisplayName()); // 以太网适配器, WiFi
System.out.println("是否启动: " + ni.isUp()); // true/false
System.out.println("是否回环: " + ni.isLoopback()); // 是否是回环接口
System.out.println("是否虚拟: " + ni.isVirtual()); // 是否是虚拟接口
System.out.println("MTU: " + ni.getMTU()); // 最大传输单元
// 获取MAC地址
byte[] mac = ni.getHardwareAddress();
if (mac != null) {
System.out.print("MAC地址: ");
for (byte b : mac) {
System.out.printf("%02X:", b);
}
System.out.println();
}
// 获取绑定的IP地址
Enumeration<InetAddress> inetAddresses = ni.getInetAddresses();
while (inetAddresses.hasMoreElements()) {
InetAddress addr = inetAddresses.nextElement();
System.out.println(" IP: " + addr.getHostAddress());
}
System.out.println("---");
}
// 按名称获取特定接口
NetworkInterface eth0 = NetworkInterface.getByName("eth0");
NetworkInterface byIp = NetworkInterface.getByInetAddress(
InetAddress.getByName("192.168.1.100")
);
2.7 总结
| 类名 | 用途 | 常用场景 |
|---|---|---|
| InetAddress | IP地址表示 | 所有IP相关操作 |
| Inet4Address | IPv4地址 | 明确IPv4处理 |
| Inet6Address | IPv6地址 | IPv6网络 |
| InetSocketAddress | IP+端口 | Socket绑定、连接 |
| NetworkInterface | 网络接口 | 多网卡选择、MAC获取 |
三,常用协议
3.1 UDP协议
-
UDP 协议:用户数据报协议(User Datagram Protocol)
-
UDP 是面向无连接通信协议
速度快,有大小限制一次最多 64k,数据不安全,易丢失
面向无连接:数据直接发送,不确认是否连接成功。
应用场景:在线视频,语音通话,网络会议。
特点
- 无连接:不用先握手
- 不可靠:可能丢包、重复、乱序
- 简单快速:适合实时应用
- 支持广播/组播
3.2 TCP协议
-
TCP 协议:传输控制协议 TCP(Transmission Control Protocol)
-
TCP 协议是面向连接的通信协议
速度慢,没有大小限制,数据安全。
面向连接:数据发送之前会确定是否连接成功再发送数据
应用场景:下载软件,文字聊天,发送邮件。
特点
- 面向连接:三次握手建立连接
- 可靠传输:保证不丢包、不重复、按顺序
- 流量控制:防止发送过快
- 拥塞控制:防止网络拥堵
3.3 HTTP协议
HTTP(超文本传输协议)
特点
- 应用层协议:基于TCP
- 无状态:每次请求独立
- 明文传输:内容不加密
- 请求-响应模型
HTTP 消息格式
# 请求
GET /index.html HTTP/1.1 ← 请求行(方法 + URI + 版本)
Host: www.example.com ← 请求头(键值对)
User-Agent: Mozilla/5.0
Accept: text/html
(空行) ← 空行分隔
请求体(GET通常没有) ← 请求数据
# 响应
HTTP/1.1 200 OK ← 状态行(版本 + 状态码 + 描述)
Content-Type: text/html ← 响应头
Content-Length: 1234
(空行) ← 空行分隔
<html>...</html> ← 响应体
HTTP 方法
- GET:获取资源(读)
- POST:提交数据(写)
- PUT:更新资源(全量更新)
- DELETE:删除资源
- PATCH:部分更新
HTTP 状态码
- 1xx:信息提示(很少见)
- 2xx:成功(200 OK,201 Created)
- 3xx:重定向(301 永久,302 临时)
- 4xx:客户端错误(404 找不到,403 禁止访问)
- 5xx:服务器错误(500 内部错误,502 网关错误)
3.4 HTTPS协议
是什么?
- HTTP + SSL/TLS加密
- 端口443(HTTP是80)
工作原理
1. 客户端发起HTTPS请求
2. 服务器返回证书(包含公钥)
3. 客户端验证证书
4. 客户端生成随机密钥,用公钥加密后发给服务器
5. 服务器用私钥解密得到密钥
6. 双方用这个密钥对称加密通信
3.5 总结
| 特性 | UDP | TCP | HTTP | HTTPS |
|---|---|---|---|---|
| 连接 | 无连接 | 面向连接 | 基于TCP | 基于TCP+SSL |
| 可靠性 | 不可靠 | 可靠 | 可靠 | 可靠 |
| 速度 | 快 | 慢 | 中等 | 最慢 |
| 头部开销 | 8字节 | 20字节 | 不定 | 不定+加密开销 |
| 数据顺序 | 不保证 | 保证 | 保证 | 保证 |
| 端口 | 自定义 | 自定义 | 80 | 443 |
| 适用场景 | 实时媒体 | 文件传输 | Web API | 安全Web API |
| Java类 | DatagramSocket | Socket/ServerSocket | HttpClient | HttpClient+SSL |
一句话区分
- UDP:发微信(不管对方收没收到)
- TCP:打电话(确保对方听到)
- HTTP:快递寄信(有固定格式)
- HTTPS:加密快递寄信(安全版)
四,UDP通信程序
- 特点:无连接、不可靠通信。
- 不事先建立连接;发送端每次把要发送的数据(限制在64KB内)、接收端IP、等信息封装成一个数据包,发出去就不管了。
- Java提供了一个
java.net.Datagramsocket类来实现UDP通信:
DatagramSocket:用于创建客户端、服务端
| 构造器 | 说明 |
|---|---|
| public DatagramSocket() | 创建客户端的Socket对象,系统会随机分配一个端口号 |
| public DatagramSocket(int port) | 创建服务端的Socket对象,并指定端口号 |
常用方法:
| 方法 | 说明 |
|---|---|
| public void send(DatagramPacket dp) | 发送数据包 |
| public void receive(DatagramPacket p) | 使用数据包接受数据 |
DatagramPacket:创建数据包
| 构造器 | 说明 |
|---|---|
| public DatagramPacket(byte[] buf,int length, InetAddress address, int port) | 创建发送出去的数据包对象 |
| public DatagramPacket(byte[] buf,int length) | 创建用来接受数据的数据包 |
常用方法
| 方法 | 说明 |
|---|---|
| public int getLength() | 获取数据包,实际接收到的字节个数 |
| public InetAddress getAddress() | 获取到发送方的ip对象 |
| public int getPort() | 获取到发送方的端口 |
举例:
//接收方
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class ReceiveMessage {
public static void main(String[] args) {
//1.创建接受数据的服务端
try(DatagramSocket ds=new DatagramSocket(8888)){
//2.创建接受数据的数据包
byte[] bytes=new byte[1024];
while(true){
DatagramPacket dp=new DatagramPacket(bytes,bytes.length);
ds.receive(dp);
//3.将接收到的数据转换为字符串并输出
//获取到发送方的ip对象
InetAddress address = dp.getAddress();
//获取到发送方的端口
int port = dp.getPort();
//4.输出接收到的数据
System.out.println("从"+address+":"+port+"接收到的数据是:"+new String(dp.getData(),0,dp.getLength()));
}
}catch(Exception e){
e.printStackTrace();
}
}
}
//发送方
import java.net.*;
import java.util.Scanner;
import static java.lang.Thread.sleep;
public class SendMessage {
public static void main(String[] args) {
//1.创建发送数据的客户端
try(DatagramSocket ds=new DatagramSocket()){
//2.创建服务端的InetAddress对象
InetAddress byName = InetAddress.getByName("127.0.0.1");
//3.创建要发送数据的数据包
while(true){
Scanner sc=new Scanner(System.in);
String dataStr = sc.nextLine();
//4.创建要发送给服务端的数据包
DatagramPacket dp=new DatagramPacket(dataStr.getBytes(),dataStr.getBytes().length,byName,8888);
//5.发送数据
ds.send(dp);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
UDP 的三种通信方式
-
单播:发送端只给一台设备发送数据(一对一)
上述写的代码就是单波形式
-
组播:发送端给一组设备发送数据(一对多)
组波地址:224.0.0.0 到239.255.255.255,其中 224.0.0.0 到 224.0.0.255 为预留的组播地址。
我们只能用这部分预留的组播地址。
组播和 IP 的区别是,ip 只能表示一台设备,组播可以表示多台设备。
-
广播:发送端给局域网所有的设备发送数据(一对所有)
广播地址:255.255.255.255
组波代码实现:
组播和单波代码实现的区别:
- 发送端和接收端使用
MulticastSocket对象来代替DatagramSocket - 发送端使用组播地址代替ip地址
- 接收端需要额外的将当前本机加入指定组播地址当中
-
发送数据
package Text2; import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; public class Send { public static void main(String[] args) throws IOException { //1.创建MulticastSocket对象 //MulticastSocket和DatagramSocket使用方式一样 MulticastSocket ms=new MulticastSocket(1010); //创建DatagramPacket对象 String s="hello world"; byte[] bytes = s.getBytes(); InetAddress address = InetAddress.getByName("224.0.0.1");//指定的是组播地址 int port=1000; DatagramPacket dp=new DatagramPacket(bytes,bytes.length,address,port); ms.send(dp); ms.close(); } } -
接收数据
package Text2; import javax.xml.crypto.Data; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.MulticastSocket; public class Receive { public static void main(String[] args) throws IOException { //创建MulticastSocket对象 MulticastSocket ms=new MulticastSocket(1000); //将当前本机,添加到224.0.0.1这一组 InetAddress address=InetAddress.getByName("224.0.0.1"); ms.joinGroup(address); //创建DatagramPacket数据包对象 byte[] bytes = new byte[1024]; DatagramPacket dp=new DatagramPacket(bytes,bytes.length); //接收数据 ms.receive(dp); //解析数据 byte[] data = dp.getData(); int len=dp.getLength(); String ip=dp.getAddress().getHostAddress(); String name=dp.getAddress().getHostName(); System.out.println("ip为:"+ip+"主机名为:"+name+"的人,发送了数据:"+new String(data,len)); //释放资源 ms.close(); } }
** 广播的代码实现:** 只需要在单波的代码中发送端额发送地址修改为255.255.255.255即可实现广播
五,TCP通信程序
5.1 TCP的三次握手和四次挥手
-
三次握手:目的是保证连接的建立

-
四次挥手:目的是确保连接端口,且通道内数据处理完毕。

5.2 TCP通信快速入门
- 特点:面向连接、可靠通信,
- 通信双方事先会采用“三次握手”方式建立可靠连接,实现端到端的通信;底层能保证数据成功传给服务端
- Java提供了一个
java.net.Socket类来实现TCP通信。

5.2.1 客户端
| 构造器 | 说明 |
|---|---|
| public Socket(String host,int port) | 根据指定的服务器ip,端口号请求与服务端建立连接,连接通过就获得了客户端socket |
方法:
| 方法 | 说明 |
|---|---|
| public OutputStream getOutputStream() | 获得字节输出流对象 |
| public InputStream getInputStream() | 获得字节输入流对象 |
| public InetAddress getInetAddress() | 获取客户端的ip对象 |
代码实现:
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
//1.创建Socket对象,同时请求与服务器程序的连接
try(Socket socket=new Socket("127.0.0.1",8888)){
//2.从socket通道中获取输出流
OutputStream outputStream = socket.getOutputStream();
//3.包装
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
Scanner sc=new Scanner(System.in);
//4.输入数据
while(true){
System.out.print("请输入内容:");
String msg=sc.nextLine();
if("exit".equals(msg)){
break;
}
dataOutputStream.writeUTF(msg);
//刷新缓存
dataOutputStream.flush();
}
}catch(Exception e){
System.out.println("服务端访问失败!");
}
}
}
5.2.2 服务端
服务端是通过java.net包下的Serversocket类来实现的
ServerSocket:
| 构造器 | 说明 |
|---|---|
| public ServerSocket(int port) | 为服务端程序注册端口 |
常用方法:
| 方法 | 说明 |
|---|---|
| public Socket accept() | 阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象 |
代码:
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) {
System.out.println("服务器启动");
//1.创建ServerSocket对象,同时为服务器注册端口
try(ServerSocket serverSocket = new ServerSocket(8888)){
//2.使用serverSocket调用accept方法获取到客户端Socket
Socket accept = serverSocket.accept();
//3.从客户端socket中获得输入流
InputStream inputStream = accept.getInputStream();
//4.包装成数据输入流
DataInputStream ds = new DataInputStream(inputStream);
//5.读取数据
System.out.println("客户端:"+accept.getRemoteSocketAddress()+"上线!");
while(true){
try {
String msg = ds.readUTF();
System.out.println("客户端说:"+msg);
} catch (Exception e) {
//捕获到异常代表客户端断开连接
System.out.println("客户端:"+accept.getRemoteSocketAddress()+"客户端断开连接!");
ds.close();
break;
}
}
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println("服务器关闭");
}
}
}
当我们客户端直接退出了,服务端就抛出异常
5.3 与多个客户端同时通信
上述快速入门案例只能实现了一对一通信,通过多线程来实现与多个客户端同时通信
** 代码实现:** 只需将服务端接受 socket 改成循环即然后配套使用多线程即可
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) {
System.out.println("服务器启动");
//1.创建ServerSocket对象,同时为服务器注册端口
try(ServerSocket serverSocket = new ServerSocket(8888)){
//2.使用循环来接受客户端请求
while(true){
Socket accept = serverSocket.accept();
ServerReadThread serverReadThread = new ServerReadThread(accept);
serverReadThread.start();
}
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println("服务器关闭");
}
}
}
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.Socket;
public class ServerReadThread extends Thread{
private Socket accept;
public ServerReadThread(Socket accept) {
this.accept = accept;
}
@Override
public void run() {
try{
//1.从客户端socket中获得输入流
InputStream inputStream = accept.getInputStream();
//2.包装成数据输入流
DataInputStream ds = new DataInputStream(inputStream);
//3.读取数据
System.out.println("客户端:"+accept.getRemoteSocketAddress()+"上线!");
while(true){
try {
String msg = ds.readUTF();
System.out.println("客户端说:"+msg);
} catch (Exception e) {
//捕获到异常代表客户端断开连接
System.out.println("客户端:"+accept.getRemoteSocketAddress()+"客户端断开连接!");
ds.close();
break;
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
5.4 实现群聊

代码实现:
服务端:
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class Server {
//代表所有在线的客户端socket
public static List<Socket> onlineSocketList=new ArrayList<Socket>();
public static void main(String[] args) {
System.out.println("服务器启动");
//1.创建ServerSocket对象,同时为服务器注册端口
try(ServerSocket serverSocket = new ServerSocket(8888)){
//2.使用循环来接受客户端请求
while(true){
Socket accept = serverSocket.accept();
onlineSocketList.add(accept);
ServerReadThread serverReadThread = new ServerReadThread(accept);
serverReadThread.start();
}
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println("服务器关闭");
}
}
}
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketAddress;
public class ServerReadThread extends Thread{
private Socket accept;
public ServerReadThread(Socket accept) {
this.accept = accept;
}
@Override
public void run() {
try{
//1.从客户端socket中获得输入流
InputStream inputStream = accept.getInputStream();
//2.包装成数据输入流
DataInputStream ds = new DataInputStream(inputStream);
//3.读取数据
System.out.println("客户端:"+accept.getRemoteSocketAddress()+"上线!");
while(true){
try {
String msg = ds.readUTF();
sendMsgAll(msg);
// System.out.println("客户端说:"+msg);
} catch (Exception e) {
//捕获到异常代表客户端断开连接
String msg = "客户端:"+accept.getRemoteSocketAddress()+"客户端断开连接!";
System.out.println(msg);
//从集合中删除掉该客户端
Server.onlineSocketList.remove(accept);
ds.close();
break;
}
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 把消息发送给所有在线客户端
* @param msg
*/
private void sendMsgAll(String msg) {
for (Socket socket : Server.onlineSocketList) {
try {
//1.从客户端socket中获得输出流
OutputStream outputStream = socket.getOutputStream();
//2.包装成数据输出流
DataOutputStream ds = new DataOutputStream(outputStream);
//3.发送数据
ds.writeUTF(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
客户端:
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
//1.创建Socket对象,同时请求与服务器程序的连接
try(Socket socket=new Socket("127.0.0.1",8888)){
//2.从socket通道中获取输出流
OutputStream outputStream = socket.getOutputStream();
//3.包装
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
Scanner sc=new Scanner(System.in);
//创建一个独立的线程随时从服务端接受消息
new ClientReadThread(socket).start();
//4.输入数据
while(true){
String msg=sc.nextLine();
if("exit".equals(msg)){
break;
}
dataOutputStream.writeUTF(msg);
//刷新缓存
dataOutputStream.flush();
}
}catch(Exception e){
System.out.println("服务端访问失败!");
}
}
}
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.Socket;
public class ClientReadThread extends Thread{
private Socket socket;
public ClientReadThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try{
//1.从客户端socket中获得输入流
InputStream inputStream = socket.getInputStream();
//2.包装成数据输入流
DataInputStream ds = new DataInputStream(inputStream);
//3.读取数据
while(true){
try {
String msg = ds.readUTF();
System.out.println(msg);
} catch (Exception e) {
//捕获到异常代表客户端断开连接
String msg = "客户端:"+ socket.getRemoteSocketAddress()+"客户端断开连接!";
System.out.println(msg);
ds.close();
break;
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
5.5 实现简易的HTTP协议交互

代码举例:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class BsServer {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
10,
20,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10),
new ThreadPoolExecutor.CallerRunsPolicy()
);
try {
ServerSocket serverSocket = new ServerSocket(8080);
while (true) {
Socket accept = serverSocket.accept();
threadPoolExecutor.execute(new BsServerReadThread(accept));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketAddress;
public class BsServerReadThread implements Runnable {
private Socket socket;
public BsServerReadThread(Socket socket) {
this.socket=socket;
}
@Override
public void run() {
SocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();
System.out.println("客户端"+remoteSocketAddress+"已连接");
try {
// 这里用PrintWriter是为了格式化输出用的,读取数据用DataInputStream来读取协议
OutputStream outputStream = socket.getOutputStream();
PrintWriter writer = new PrintWriter(outputStream);
//输出http协议
writer.println("HTTP/1.1 200 OK");//响应行
writer.println("Content-Type:text/html;charset=utf-8");//响应头
writer.println("<html><head><title>bs</title></head><body><h1>测试内容</h1></body></html>");//响应体
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}