TCP程序有主次之分,一个是服务器程序,另一个是客户机程序。它们的交互规则如下图:
![](https://img.kancloud.cn/3b/14/3b14fa1d95584b48d72765eb2fb7ed04_845x598.png)
*模拟服务器和客户端的方法:分在使用eclipse创建两个独立的工作空间,一个编写TCP服务端程序,另一个编写TCP客户端程序。编写好后,先运行TCP服务端程序,再运行TCP客户端程序。或者使用命令行业可以,请先往下看。*
**`net/server/TcpServer.java`**(服务端)
```java
package net.server;
import java.io.*;
import java.net.*;
import java.util.Random;
/**
* TCP 服务端程序
* @version 2020/10/21
*
*/
public class TcpServer {
public static void main(String[] args) {
new TcpServer().getServer();
}
private BufferedReader reader;
private ServerSocket server;
private Socket socket;
private PrintWriter printWriter;
private Random random = new Random();
/**
* 服务器与客户端的连接,接收客户端的请求并响应客户端的请求
*/
void getServer() {
try {
server = new ServerSocket(5000); // 为服务器创建一个为5000的端口号
System.out.println("服务器套接字已创建成功");
while(true) {
// 等待客户机连接
System.out.println("等待客户机的连接...");
// 当有客户机连接时,accept返回一个新的Socket对象与其客户端的Socket对象交互,否则一直阻塞
socket = server.accept();
System.out.println("已有客户端连接");
// 该对象负责获取客户端的请求信息
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 该对象负责响应客户端
printWriter = new PrintWriter(socket.getOutputStream(), true);
while(true) {
String message = reader.readLine(); // 获取客户端的请求信息
System.out.println("客户端:" + message);
// 当客户端输入exit时,表明该客户端已断开请求
if("exit".equals(message)) {
System.out.println("客户端已断开连接!\n");
// 服务器响应客户端的请求,发送一段字符串给客户端
printWriter.println("你已退出!");
break;
}
// 服务器响应客户端的请求,发送一段字符串给客户端
printWriter.println("我已响应你想要的资源了!" + random.nextInt(1000));
}
reader.close();
printWriter.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
**`net/client/TcpClient.java`** (客户端)
```
package net.client;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class TcpClient {
public static void main(String[] args) throws IOException, InterruptedException {
new TcpClient().connect();
}
private Socket socket;
private PrintWriter printWriter;
private String message = "connect";
private Scanner input = new Scanner(System.in);
private BufferedReader bufferedReader;
/**
* 连接服务器并发送请求信息
* @throws IOException
*/
public void connect() throws IOException, InterruptedException {
System.out.println("正在尝试连接服务器...");
socket = new Socket("127.0.0.1", 5000); // 指定服务端的IP地址和端口
System.out.println("连接成功!");
// 该对象负责将客户端的请求发送到服务端
printWriter = new PrintWriter(socket.getOutputStream(), true);
// 该对象负责获取服务端的响应
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(!"exit".equals(message)) {
System.out.print(">>");
message = input.nextLine();
printWriter.println(message); // 发送请求信息到服务端
Thread.sleep(1000);
// 获取服务端的响应
System.out.println("服务器:" + bufferedReader.readLine());
}
socket.close();
printWriter.close();
input.close();
bufferedReader.close();
}
}
```
```
打开第一个cmd窗口执行服务端程序:
编译源码:javac TcpServer.java -encoding utf-8
执行程序:java net.server.TcpServer
打开第二个cmd窗口执行客户端程序:
编译源码:javac TcpClient.java -encoding utf-8
执行程序:java net.client.TcpClient
```
结果如下:
![](https://img.kancloud.cn/90/7f/907f31b30a3f82c05caa3c256c19845f_1086x611.gif)
- 网络通信
- 网络协议
- 端口和套接字
- TCP网络程序
- UDP网络程序
- 多线程聊天室
- 多线程
- 线程相关概念
- 线程实现方式
- 中断线程
- 线程生命周期
- 线程优先级
- 优先级规则
- 案例演示
- 线程同步机制
- 线程同步机制
- synchronized关键字
- ReentrantLock类
- Condition类
- 监视器概念
- volatile关键字
- final变量
- 死锁
- 线程局部变量
- 读/写锁
- 原子类
- 阻塞队列
- 工作规则
- 案例演示
- 常用阻塞队列
- 线程安全集合
- 高效的映射/集/队列
- 并发集视图
- 写数组的拷贝
- Arrays类的并行数组算法
- 同步包装器
- Callable与Future
- 执行器
- 线程池
- 预定执行
- 控制任务组
- Fork-Join框架
- 同步器
- 同步器
- 信号量
- CountDownLatch类
- CyclicBarrier类
- Exchanger类
- SynchronousQueue类
- 线程与Swing
- Swing与线程问题
- 两个原则
- Swing工作线程
- 单一线程规则
- 文件IO
- File类
- 文件输入输出
- ZIP压缩文件
- 集合
- 集合框架
- 集合接口
- 集合实现类
- 线程安全集合
- 集合算法
- 迭代器
- 集合排序
- JDBC
- JDBC是什么
- JDBC-ODBC桥
- JDBC驱动程序类型
- JDBC常用类与接口
- 数据库操作
- 连接数据库
- 增/删/改/查/预处理
- 事务
- 批处理
- commons-dbutils工具
- 安全问题
- Jedis
- 使用Jedis操作Redis数据库
- JSON转换
- 使用连接池
- 案例
- 单例破坏
- 单例定义
- 单例实现方式
- 懒汉式实现单例
- 饿汉式实现单例
- 单例破坏
- 类的单例破坏
- 枚举的单例破坏
- 克隆
- 克隆是什么
- 浅克隆
- 深克隆
- 注解
- 注解是什么
- 三大注解
- 内置注解
- 元注解
- 自定义注解
- NIO
- 相关概念
- BIO/NIO/AIO
- 多线程编程
- 线程同步
- 线程通信
- NIO
- NIO三大核心组件
- NIO网络编程
- NIO文件读写
- AIO
- Java8新特性
- Lambda表达式
- 方法引用
- 函数式接口
- 默认方法
- 什么是默认方法
- 默认方法语法格式
- 多个同名的默认方法问题
- 静态默认方法
- 默认方法实例
- Stream
- Stream是什么
- Stream示例
- Optional容器
- 新的日期时间API
- Base64
- SPI
- SPI是什么
- SPI与API的区别
- 常见场景
- 使用SPI需遵循的约定
- SPI使用步骤