【Java 网络编程】TCP 服务器端 客户端 简单示例
I IntelliJ IDEA 创建 Java 项目
Java 程序使用 IntelliJ IDEA 进行开发 ;
创建客户端项目 :
-
① 菜单栏 File -> New Project , 弹出 New Project 对话框 , 选择 Gradle 类型下的 java 项目 ;
-
② 输入 GroupId 和 项目名称 , 一直点击下一步到结束 , 最后一个对话框注意选择项目所在位置 ;
II 客户端 Socket 创建
创建 Socket 需要设置超时时长 , 要连接的服务器端的端点信息 , 该端点包括 IP 地址和端口号 ;
//1. 创建 Socket 对象
Socket socket = new Socket();
//2. 设置 Socket 的超时时间
socket.setSoTimeout(5000);
//3. 创建连接的端点 , 该端点包括 IP 地址和端口号
InetSocketAddress inetSocketAddress =
new InetSocketAddress(
Inet4Address.getLocalHost(), //本机IP地址
8000 //端口号
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
III Socket 客户端连接服务器端
调用 Socket 对象的 connect 方法 , 即可发起对服务器的连接 , 如果连接成功 , 则会继续执行 , 如果连接失败或者超时 , 会抛出异常 ;
//4.. 连接服务器端点 , 并设置超时时间
socket.connect(inetSocketAddress, 5000);
- 1
- 2
IV Socket 两个端点信息获取
1. 获取服务器端点的 IP 地址和端口号 : 调用 Socket 对象的 getInetAddress 方法获取服务器端 IP 地址 , 调用 getPort 方法获取服务器端的端口号 ;
//1. 获取服务器 IP 地址
InetAddress serverAddress = socket.getInetAddress();
//2. 获取服务器端口号
int serverPort = socket.getPort();
- 1
- 2
- 3
- 4
2. 获取客户端端点的 IP 地址和端口号 : 调用 Socket 对象的 getLocalAddress 方法 , 可以获取客户端的 IP 地址 , 调用 getLocalPort 方法可以获取客户端的端口号 ;
//3. 获取客户端 IP 地址
InetAddress clientAddress = socket.getLocalAddress();
//4. 获取客户端端口号
int clientPort = socket.getLocalPort();
- 1
- 2
- 3
- 4
V 控制台人机交互
客户端信息获取 ( 人机交互 ) : 控制台中等待用户输入 , BufferedReader 的 readLine 方法 , 可以在控制台中阻塞等待用户输入 , 用户可以在控制台输入信息 , 然后客户端将该信息传给服务器 ; 下面是键盘输入流的创建和使用过程
//1. 获取控制台输入流
InputStream is = System.in;
//2. 该输入流会阻塞 , 等待用户控制台输入
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//4. 阻塞命令行 , 等待用户输入一行数据, 并存入 string 对象中
String string = br.readLine();
- 1
- 2
- 3
- 4
- 5
- 6
VI Socket 客户端与服务器端交互
服务器 -> 客户端 : 客户端阻塞等待服务器端发送数据 , 从 Socket 中获取 BufferedReader 输入流 , 根据输入流创建 BufferedReader , 调用 readLine 方法阻塞等待服务器传回信息 ;
//1. 获取服务器端输入流
cisFromServer = socket.getInputStream();
//2. 将输入流转为 BufferedReader
BufferedReader brFromServer = new BufferedReader(new InputStreamReader(isFromServer));
//6. 阻塞控制台 , 从服务器读取一行数据
String stringFromServer = brFromServer.readLine();
- 1
- 2
- 3
- 4
- 5
- 6
客户端 -> 服务器 : 从 Socket 中获取输出流 OutputStream , 根据该输出流创建 PrintStream , 可以将字符串输出到客户端 ;
//4. 获取客户端的输出流 , 用于向服务器端写出数据
OutputStream os = socket.getOutputStream();
//5. 创建打印流 , 用于向服务器端写出字符
PrintStream ps = new PrintStream(os);
//5. 通过打印流 , 将该字符串传输给服务器端
ps.println(string);
- 1
- 2
- 3
- 4
- 5
- 6
VII ServerSocket 服务器端端口监听
创建 ServerSocket 对象 , 只需要指定端口即可 , 不需要指定 IP 地址 , 其 IP 地址就是本机的 IP 地址 , 如果机器有多个 IP 地址 , 如果没有指定 IP 地址 , 那么会监听所有的 IP 地址的指定端口号 ;
//1. 创建服务器套接字 , 只需要指定端口即可 , 不需要指定 IP 地址
// 其 IP 地址就是本机的 IP 地址 , 如果机器有多个 IP 地址
// 如果没有指定 IP 地址 , 那么会监听所有的 IP 地址的指定端口号
ServerSocket serverSocket = new ServerSocket(8000);
- 1
- 2
- 3
- 4
VIII ServerSocket 服务器端参数获取
调用 ServerSocket 对象的 getInetAddress 获取服务器端的 IP 地址 , 调用该对象的 getLocalPort 可以获取服务器端监听的端口号 ;
//2. 获取服务器端 IP 地址
InetAddress inetAddress = serverSocket.getInetAddress();
//3. 获取服务器端口号
int localPort = serverSocket.getLocalPort();
- 1
- 2
- 3
- 4
- 5
IX ServerSocket 服务器端同时与多个客户端交互方案
将与单个客户端交互的操作封装到线程中 , 每当与一个新的客户端建立连接 , 就开启一个异步线程处理与该客户端之间的交互 ;
客户端处理线程 :
/**
* 异步线程 , 处理单个客户端连接
* 如果多个客户端连接 , 就需要创建多个该类, 同时处理多个客户端连接
*/
public static class ClientHandler extends Thread{
//1. 客户端 Socket 连接
private Socket clientSocket;
public ClientHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
无限循环等待客户端连接 , 一旦连接成功 , 就开启一个异步线程 ;
//II. 等待客户端连接, 注意此处是无限循环连接
while(true){
//1. 收到一个客户端连接请求 , 获取 客户端 Socket 连接
Socket clientSocket = serverSocket.accept();
//2. 将 Socket 连接传入 ClientHandler 线程 , 异步处理与客户端交互操作
ClientHandler clientHandler = new ClientHandler(clientSocket);
//3. 启动 与客户端 Socket 交互处理 异步线程
clientHandler.start();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
X Socket 客户端代码示例
import java.io.*;
import java.net.*;
/**
* 客户端
*/
public class Client {
/**
* 客户端入口函数
* @param args
*/
public static void main(String[] args){
try {
//I. 连接
//1. 创建 Socket 对象
Socket socket = new Socket();
//2. 设置 Socket 的超时时间
socket.setSoTimeout(5000);
//3. 创建连接的端点 , 该端点包括 IP 地址和端口号
InetSocketAddress inetSocketAddress =
new InetSocketAddress(
Inet4Address.getLocalHost(), //本机IP地址
8000 //端口号
);
//4.. 连接服务器端点 , 并设置超时时间
socket.connect(inetSocketAddress, 5000);
//5. 如果连接成功会继续执行下面的操作, 如果失败会根据失败情况抛出异常
//II. 获取 Socket 连接两个端点的属性, IP 地址和端口号
//1. 获取服务器 IP 地址
InetAddress serverAddress = socket.getInetAddress();
//2. 获取服务器端口号
int serverPort = socket.getPort();
//3. 获取客户端 IP 地址
InetAddress clientAddress = socket.getLocalAddress();
//4. 获取客户端端口号
int clientPort = socket.getLocalPort();
System.out.println("服务器连接成功\n服务器地址 : " + serverAddress +
" , 服务器端口号 : " + serverAddress +
"\n客户端地址 : " + clientAddress + " , 客户端端口号 : " + clientPort);
//向服务器端发送数据
sendToServer(socket);
//III. 关闭 Socket 连接
socket.close();
System.out.println("客户端 Socket 连接关闭");
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//客户端可能挂了 , 需要重启
}
}
public static void sendToServer(Socket socket){
try {
//I. 获取用户控制台输入信息
//1. 获取控制台输入流
InputStream is = System.in;
//2. 该输入流会阻塞 , 等待用户控制台输入
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//II. 将用户输入信息上传到服务器
//4. 获取客户端的输出流 , 用于向服务器端写出数据
OutputStream os = socket.getOutputStream();
//5. 创建打印流 , 用于向服务器端写出字符
PrintStream ps = new PrintStream(os);
//III. 从服务器获取信息 , 这里循环读取数据, 接收到 服务器端的 quit 字符串才退出
//1. 获取服务器端输入流
InputStream isFromServer = socket.getInputStream();
//2. 将输入流转为 BufferedReader
BufferedReader brFromServer = new BufferedReader(new InputStreamReader(isFromServer));
//3. 循环控制变量 , 退出时设置为 false
boolean isReadFromServer = true;
while (isReadFromServer){
//4. 阻塞命令行 , 等待用户输入一行数据, 并存入 string 对象中
String string = br.readLine();
//5. 通过打印流 , 将该字符串传输给服务器端
ps.println(string);
//6. 阻塞控制台 , 从服务器读取一行数据
String stringFromServer = brFromServer.readLine();
//7. 根据服务器返回的数据进行不同操作
if("quit".equals(stringFromServer)){
//停止循环
isReadFromServer = false;
}else{
System.out.println(stringFromServer);
}
}
//IV. 释放资源
br.close();
ps.close();
brFromServer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
XI Socket 服务器端代码示例
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务器端
*/
public class Server {
/**
* 服务器端入口函数
* @param args
*/
public static void main(String[] args){
try {
//I. 创建服务器套接字, 并监听端口
//1. 创建服务器套接字 , 只需要指定端口即可 , 不需要指定 IP 地址
// 其 IP 地址就是本机的 IP 地址 , 如果机器有多个 IP 地址
// 如果没有指定 IP 地址 , 那么会监听所有的 IP 地址的指定端口号
ServerSocket serverSocket = new ServerSocket(8000);
//2. 获取服务器端 IP 地址
InetAddress inetAddress = serverSocket.getInetAddress();
//3. 获取服务器端口号
int localPort = serverSocket.getLocalPort();
System.out.println("服务器开启\nIP 地址 : " + inetAddress + " , 端口号 : " + localPort);
//II. 等待客户端连接, 注意此处是无限循环连接
while(true){
//1. 收到一个客户端连接请求 , 获取 客户端 Socket 连接
Socket clientSocket = serverSocket.accept();
//2. 将 Socket 连接传入 ClientHandler 线程 , 异步处理与客户端交互操作
ClientHandler clientHandler = new ClientHandler(clientSocket);
//3. 启动 与客户端 Socket 交互处理 异步线程
clientHandler.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 异步线程 , 处理单个客户端连接
* 如果多个客户端连接 , 就需要创建多个该类, 同时处理多个客户端连接
*/
public static class ClientHandler extends Thread{
//1. 客户端 Socket 连接
private Socket clientSocket;
//2. 循环控制变量
private boolean loopFlag = true;
public ClientHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
@Override
public void run() {
super.run();
//I. 获取客户端相关信息
//1. 获取客户端的 IP 地址
InetAddress inetAddress = clientSocket.getInetAddress();
//2. 获取客户端的端口号
int port = clientSocket.getPort();
//3. 打印客户端的信息
System.out.println("客户端信息 : \nIP 地址 : " + inetAddress + " , 端口号 : " + port);
try {
//II. 创建与客户端交互的输入输出流
//1. 获取客户端 Socket 输出流 , 用于向客户端发送数据
OutputStream os = clientSocket.getOutputStream();
//2. 创建打印流 , 用于向客户端输出数据
PrintStream ps = new PrintStream(os);
//3. 获取客户端 Socket 输入流 , 用于接收客户端数据
InputStream is = clientSocket.getInputStream();
//4. 获取客户端的字符输入流 , 该输入流可以阻塞等待客户端输入
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//III. 循环处理与客户端交互的信息
while (loopFlag){
//1. 等待客户端输入
String string = br.readLine();
//2. 处理客户端输入
if("quit".equals(string)){
//如果客户端发送退出, 那么停止循环, 将该信息在送回客户端
loopFlag = false;
//将信息发送到客户端
ps.println("quit");
}else{
//将信息打印到控制台
System.out.println(string);
//将发送成功信息返回给客户端
ps.println("发送成功 , 大小 " + string.length() + " 字节");
}
}
//IV. 关闭相关资源
ps.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
//如果出现异常 , 将该 Socket 关闭
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("客户端退出 : \nIP 地址 : " + inetAddress + " , 端口号 : " + port);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
XII 运行客户端与服务器端代码
1. 编译两个 Java 代码 : 选择菜单栏 -> Build -> Rebuild Project 选项 , 获取到 Client.class 和 Server.class 文件 ;
2. 字节码文件地址 : 编译后的 class 字节码文件在工程目录的 out\production\classes 目录下 ;
打开两个命令行界面 , 首先进入该目录 , 先运行服务器端 , 在命令行中输入 java Server , 即开启了服务器端 ; 再打开客户端 , 在另一个命令行中运行 java Client , 即开启了客户端 ;
客户端输入文字 , 与服务器端交互 :
文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。
原文链接:hanshuliang.blog.csdn.net/article/details/100130633
- 点赞
- 收藏
- 关注作者
评论(0)