Java网络编程详解:Socket与ServerSocket
Java网络编程详解:Socket与ServerSocket
概述
Java提供了丰富的网络编程API,支持TCP和UDP协议。本教程介绍Socket编程和NIO网络编程。
1. TCP Socket编程
服务器端
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8080)) {
System.out.println("服务器启动,等待连接...");
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("客户端已连接: " + clientSocket.getInetAddress());
// 处理客户端请求
new Thread(() -> handleClient(clientSocket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void handleClient(Socket clientSocket) {
try (BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("收到: " + inputLine);
out.println("服务器收到: " + inputLine);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 8080);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()))) {
// 发送消息
out.println("Hello Server!");
String response = in.readLine();
System.out.println("服务器响应: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. UDP Socket编程
import java.net.*;
import java.util.*;
public class UDPServer {
public static void main(String[] args) {
try (DatagramSocket socket = new DatagramSocket(9090)) {
System.out.println("UDP服务器启动...");
byte[] buffer = new byte[1024];
while (true) {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
String message = new String(packet.getData(), 0, packet.getLength());
System.out.println("收到: " + message);
// 发送响应
InetAddress address = packet.getAddress();
int port = packet.getPort();
String response = "UDP响应: " + message;
DatagramPacket responsePacket = new DatagramPacket(
response.getBytes(), response.length(), address, port);
socket.send(responsePacket);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class UDPClient {
public static void main(String[] args) {
try (DatagramSocket socket = new DatagramSocket()) {
InetAddress address = InetAddress.getByName("localhost");
String message = "Hello UDP Server!";
DatagramPacket packet = new DatagramPacket(
message.getBytes(), message.length(), address, 9090);
socket.send(packet);
// 接收响应
byte[] buffer = new byte[1024];
DatagramPacket responsePacket = new DatagramPacket(buffer, buffer.length);
socket.receive(responsePacket);
String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
System.out.println("服务器响应: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. NIO网络编程
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.util.*;
public class NIOServer {
public static void main(String[] args) {
try {
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(new java.net.InetSocketAddress(8080));
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIO服务器启动...");
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
System.out.println("新连接: " + client.getRemoteAddress());
} else if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = client.read(buffer);
if (bytesRead > 0) {
buffer.flip();
String message = StandardCharsets.UTF_8.decode(buffer).toString();
System.out.println("收到: " + message);
// 发送响应
String response = "NIO响应: " + message;
ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
client.write(responseBuffer);
}
}
keyIterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4. 实际应用示例
简单的聊天服务器
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
public class ChatServer {
private static final Set<PrintWriter> clients = ConcurrentHashMap.newKeySet();
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8080)) {
System.out.println("聊天服务器启动...");
while (true) {
Socket clientSocket = serverSocket.accept();
new Thread(() -> handleClient(clientSocket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void handleClient(Socket clientSocket) {
try (BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
clients.add(out);
String message;
while ((message = in.readLine()) != null) {
System.out.println("消息: " + message);
broadcast(message);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 移除客户端
clients.removeIf(out -> out.checkError());
}
}
private static void broadcast(String message) {
for (PrintWriter client : clients) {
client.println(message);
}
}
}
5. 最佳实践
- 使用try-with-resources:自动关闭资源
- 使用NIO:高并发场景使用NIO
- 处理异常:妥善处理IOException
- 使用线程池:管理客户端连接
- 设置超时:避免长时间阻塞
总结
Java网络编程提供了丰富的API。掌握Socket编程和NIO网络编程,可以实现各种网络应用。在实际编程中,要根据需求选择合适的网络编程方式。