Java TCP Socket 编程实战:聊天室服务端与客户端实现
Java 网络编程中,Socket 是 TCP/IP 协议的核心抽象。本文将从概念入手,解析 Socket 的地址组成与连接机制,并通过服务端(ChatServer)和客户端(ChatClient)的完整代码,演示如何使用 InputStream 和 OutputStream 进行可靠的数据收发,重点说明 flush() 在强制刷新数据缓冲中的作用。
TCP Socket 核心概念与地址结构
Socket 是一个抽象层,应用程序通过它建立远程连接,底层由操作系统通过 TCP/IP 协议栈传输数据。之所以需要 Socket,是因为仅靠 IP 地址无法区分同一台计算机上运行的多个应用(如浏览器、QQ等)。操作系统通过 IP 地址 + 端口号(即 Socket 组合)来唯一标识一个网络连接。
端口号的分配规则如下:
- 0~1023:特权端口,通常需要管理员权限(如 80, 443)。
- 1024~65535:用户可用端口,普通应用程序可自由分配。
在网络通信模型中,服务器端需主动监听指定端口,等待客户端发起连接请求。连接成功后,双方将各自获得独立的 Socket 实体:服务器端的 Socket 对应固定监听端口,而客户端的 Socket 则使用动态分配的随机端口,从而确立一条全双工的 TCP 通路。
服务端实现:ChatServer
服务端的职责是创建监听对象、接受连接并响应数据。以下示例创建一个简单的对话服务端,监听端口 9966。
第1步:启动监听与预置数据
目的:初始化 ServerSocket 绑定端口,并准备映射字典用于回答。
package com.ljl.tcp.demo2;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class ChatServer {
public static void main(String[] args) {
// 预置问答映射表
Map<String, String> chatMap = new HashMap<String, String>(){
{
put("你好", "你好呀");
put("hi", "hi~");
put("hello", "哈喽");
put("吃了吗", "没呢,你呢");
put("孤勇者", "爱你孤身走暗巷");
put("有请潘周聃", "潘周聃,今年29岁,苏黎世理工大学.....");
put("很高兴认识你", "我也是哦");
}
};
try (ServerSocket server = new ServerSocket(9966)) { // 监听9966端口
while(true) {
// 阻塞直到有客户端连接
Socket client = server.accept();
String clientIP = client.getInetAddress().getHostAddress();
System.out.println("客户端连接成功: " + clientIP);
try(
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));){
String question = reader.readLine();
System.out.println("来自 " + clientIP + " 的提问:" + question);
String answer = chatMap.get(question);
answer = answer == null ? "我不知道你在说啥" : answer;
writer.write(answer);
//注意:此处未调用flush,依赖关闭流触发输出,实际生产建议显式flush
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端实现:ChatClient
客户端需要主动连接服务器的 IP 和端口,发送消息并读取反馈。
第2步:建立连接与交互循环
目的:配置本地 IP(如 192.168.254.163),通过控制台输入发送请求,利用 shutdownOutput() 结束当前数据的写入通道以触发服务端读取。
package com.ljl.tcp.demo2;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
public class ChatClient {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
while(true) {
try (
// 替换为目标服务器IP
Socket client = new Socket("192.168.254.163",9966);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
){
String question = input.nextLine();
if("退下".equals(question)) break;
// 发送请求
writer.write(question);
writer.flush(); // 重要:强制将数据推送到网络
client.shutdownOutput(); // 标记写入结束
String answer = reader.readLine();
System.out.println("服务器回答:" + answer);
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("over");
}
}数据流传输机制与注意事项
TCP 是面向连接的流协议,在 Java 中,Socket 实例提供了操作底层的 IO 流:
// 读取网络输入流
InputStream in = sock.getInputStream();
// 写入网络输出流
OutputStream out = sock.getOutputStream();
关于 Flush 的重要性: 在向网络写入数据时,系统会先将数据放入内存缓冲区。如果不调用 flush(),当缓冲区未满或程序结束时,数据可能滞留在内存中无法到达对端。因此,在每次 write() 后必须调用 flush() 以确保数据实时发送。
总结
- 服务器端使用
ServerSocket监听特定端口,调用accept()接收客户端。 - 客户端使用
Socket(InetAddress, port)发起连接。 - 通信双方的读写均通过 Socket 的
InputStream和OutputStream完成。 - 数据写入后务必调用
flush()清空缓冲区。
以上就是Java TCP Socket 编程服务端与客户端实现的详细内容,更多关于Java Socket教程的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









