Java实现Socket的几种方式
Java提供了多种方式实现Socket通信,主要包括标准Socket、SocketChannel、DatagramSocket等。本文将详细介绍这些方式的操作步骤、命令示例及注意事项。
1. 标准Socket编程
标准Socket是最基础的网络通信方式,分为服务器端和客户端。
1.1 服务器端实现
- 导入必要的包
- 创建ServerSocket实例并指定端口号
- 调用accept()方法等待客户端连接
- 通过Socket对象进行数据传输
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8888);
System.out.println("Server started on port 8888");
while(true) {
Socket client = server.accept();
System.out.println("Client connected: " + client.getInetAddress().getHostAddress());
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream(), true);
String line;
while((line = in.readLine()) != null) {
out.println("Echo: " + line);
if(line.equalsIgnoreCase("exit")) break;
}
client.close();
}
server.close();
}
}
1.2 客户端实现
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 8888);
System.out.println("Connected to server");
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String fromServer, fromUser;
while((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
fromUser = stdIn.readLine();
if(fromUser != null) {
out.println(fromUser);
if(fromUser.equalsIgnoreCase("exit")) break;
}
}
socket.close();
}
}
2. SocketChannel编程
SocketChannel是NIO中的非阻塞通信方式,提供更灵活的网络编程能力。
2.1 服务器端实现
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
server.socket().bind(new InetSocketAddress(9999));
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(true) {
selector.select();
Set keys = selector.selectedKeys();
Iterator iterator = keys.iterator();
while(iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if(key.isAcceptable()) {
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
System.out.println("Client connected: " + client.getRemoteAddress());
}
if(key.isReadable()) {
SocketChannel client = (SocketChannel)key.channel();
buffer.clear();
int read = client.read(buffer);
if(read == -1) {
client.close();
} else {
buffer.flip();
while(buffer.hasRemaining()) {
System.out.print((char)buffer.get());
}
System.out.println();
buffer.clear();
}
}
}
}
}
}
2.2 客户端实现
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
public class Client {
public static void main(String[] args) throws IOException {
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("localhost", 9999));
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_CONNECT);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(true) {
selector.select();
Set keys = selector.selectedKeys();
Iterator iterator = keys.iterator();
while(iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if(key.isConnectable()) {
SocketChannel client = (SocketChannel)key.channel();
if(client.finishConnect()) {
System.out.println("Connected to server");
client.register(selector, SelectionKey.OP_WRITE);
}
}
if(key.isWritable()) {
SocketChannel client = (SocketChannel)key.channel();
buffer.clear();
buffer.put("Hello Server".getBytes());
buffer.flip();
while(buffer.hasRemaining()) {
client.write(buffer);
}
buffer.clear();
client.register(selector, SelectionKey.OP_READ);
}
if(key.isReadable()) {
SocketChannel client = (SocketChannel)key.channel();
buffer.clear();
int read = client.read(buffer);
if(read == -1) {
client.close();
} else {
buffer.flip();
while(buffer.hasRemaining()) {
System.out.print((char)buffer.get());
}
System.out.println();
buffer.clear();
}
}
}
}
}
}
3. DatagramSocket编程
UDP协议的Socket实现,适用于不需要建立持久连接的场景。
3.1 服务器端实现
import java.io.*;
import java.net.*;
public class UdpServer {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(7777);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
System.out.println("UDP Server started on port 7777");
while(true) {
socket.receive(packet);
String message = new String(packet.getData(), 0, packet.getLength());
System.out.println("Received from " + packet.getAddress() + ": " + message);
InetAddress address = packet.getAddress();
int port = packet.getPort();
String response = "Echo: " + message;
byte[] responseBytes = response.getBytes();
packet = new DatagramPacket(responseBytes, responseBytes.length, address, port);
socket.send(packet);
}
}
}
3.2 客户端实现
import java.io.*;
import java.net.*;
public class UdpClient {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket();
InetAddress address = InetAddress.getByName("localhost");
byte[] buffer = new byte[1024];
for(int i = 0; i < 5; i++) {
String message = "Hello Server " + i;
buffer = message.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address, 7777);
socket.send(packet);
packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
String response = new String(packet.getData(), 0, packet.getLength());
System.out.println("Received from server: " + response);
}
socket.close();
}
}
注意事项和实用技巧
- 异常处理:所有网络操作都需要妥善处理IOException
- 资源管理:使用try-with-resources或finally块确保Socket关闭
- 端口选择:服务器端应选择非冲突的端口号(1024-65535)
- 性能优化:对于高并发场景,推荐使用NIO的Selector
- 安全性:避免在代码中硬编码IP地址和端口号
- 跨平台:Java Socket在所有主流操作系统上表现一致
- 调试技巧:使用telnet或nc工具测试Socket端口